Typedef enum to string in C - string

I have error typedefs as follows.
typedef enum { Connection_Error
, Parity_Error
, Data_Read_Error
} error_t;
And I have a function returning the "error_t". I would like to change the enum to string (preferably without using switch(case)).
Eg.
char str[20];
str = function_to_convert_to_string (error_t);
Something like that.
Any suggestions?

The C language does not have any built-in provision for storing symbol-names as strings in the output binary program (unlike Java and C# which have the .ToString() method) so you must manually do this in your code - fortunately it's made easier with the preprocessor's ability to convert symbols to string-literals ("stringification").
Note that typedef enum { ... } name is unnecessary, and avoid using _t as a suffix as it is reserved by the POSIX specifications.
Try this:
enum errorType {
Connection_Error,
Parity_Error,
Data_Read_Error
};
#define ERRMSG( ARG ) \
case ARG: \
return "Error: " #ARG ".";
char* getErrorMessage(errorType e) {
switch(e) {
ERRMSG( Connection_Error )
ERRMSG( Parity_Error )
ERRMSG( Data_Read_Error )
default: exit(1); // or some other error handler
}
}
Note how you see the enum is manually listed twice in code: first in the enum definition, and again in the switch block. For small enums this is fine, but if your enum list is large or changes frequently you'll want to adopt a DRY approach. You can simplify it by listing all of the enums in their own text file, like so:
ErrorTypeEnum.inc
ENTRY( Connection_Error )
ENTRY( Parity_Error )
ENTRY( Data_Read_Error )
ErrorTypeEnum.h
#define ENTRY(NAME) NAME,
enum errorType {
#include "ErrorTypeEnum.inc"
_Last
}
#undef ENTRY
The _Last entry is needed because of the trailing comma, also provides a means to get the count f elements because _Last will have a numeric value equal to the last ENTRY + 1.
ErrorTypeEnum.c
char* getErrorMessage(errorType e) {
switch(e) {
#define ENTRY(NAME) case NAME: return "Error: " #NAME ".";
#include "ErrorTypeEnum.inc"
default: exit(1); // or some other error handler
#undef
}
}
Further
You can expand upon this by adding other values to the ENTRY macro, such as custom human-readable error messages (instead of using stringification). That is an exercise left up to the reader :)

Related

Converting all variadic arguments into a single std::string via move semantics

I have a class that contains a lambda function that looks like this:
class Foo {
private:
inline static std::string text{};
public:
template<typename...T>
inline static auto func = [](T&&...args) mutable throw() {
text += std::string(args...);
};
void show() {
std::cout << text << '\n';
}
};
My intended use would be something like this:
int main() {
Foo bar;
bar.func<std::string, int, std::string>( "Hello, I am", 39, "years old!");
bar.show();
return 0;
}
I want the templated variadic lambda to take in any type of parameter that is a basic type such as string, char*, char[], int, float, double, etc... and to convert all of them into a single std::string that will be stored within the class.
When I run my code as such:
int main() {
Foo bar;
bar.func<string>( "Hello world!");
bar.show();
return 0;
}
Everything compiles fine, however, when I begin to add in various types such as the example from the intended use above, it fails to compile. Microsoft Visual Studio is giving me a C2400 compiler error: cannot convert from initialize list to std::string. No constructor could take the source type, or constructor overload resolution was ambiguous...
I believe I understand why it is ambiguous as that's not so much the issue. My question is what would be the proper and efficient way of using "move semantics or perfect forwarding"? I'm trying to avoid a bunch of copies of temporaries.
You could use fold expressions:
template<typename...T>
inline static auto func = [](T&&...args) mutable throw() {
text += (toString(args) + ...);
};
where toString is defined as:
template<class T>
std::string toString(T&& t){
if constexpr (std::is_arithmetic_v<std::decay_t<T>>)
return std::to_string(std::forward<T>(t));
else
return std::forward<T>(t);
}
you can extend toString to handle all types you need to convert to string.
Demo

Does Arduino support the struct hack or similar solution in lieu of flexible array elements?

I coded an Arduino project for my son and learned about C in the process. All works fine but after dividing up the code into ten files and grouping the variables into structs in each file I'm not able to solve one wish for clarity. We need to empirically determine the best size of an array for storing and averaging port reads so this is what I want:
struct Alarms {
// Configurable parameters
const unsigned int number_of_reads = 24;
// State variables
int reads[number_of_reads]; // Error: invalid use of non-static data member 'Alarms::num_of_reads'
};
It’s simple but doesn't work. I tried flexible array members until I found that that feature is not supported in C++. Arduino compiles with C++. I tried many examples of the 'struct hack' but they all returned errors like this one:
struct Alarms {
// Configurable parameters
int number_of_reads = 24;
// State variables
int reads[];
} ar;
void setup_alarm() {
ar.reads = malloc(sizeof(int) * ar.number_of_reads); // Error: incompatible types in assignment of 'void*' to 'int [0]'
}
That looked promising but I suspect my ignorance is glowing brightly. Most struct hack examples call for declaring the struct and later initializing the struct variables. I’m hoping to not duplicate the struct.
I considered splitting the struct but that would be error prone and, well, another compile error:
struct Alarms2 {
int reads[ar.num_of_reads]; // Error: array bound is not an integer constant before ']' token
} ar2;
An alternative is to size the array and get the size later but it needs an explanation:
struct Alarms {
// Configurable parameters
int reads[ 24 ]; // Put number of reads to average between brackets
// State variables
int number_of_reads;
};
void setup_alarm() {
ar.number_of_reads = sizeof(ar.reads) / sizeof(ar.reads[0]); // this works
}
Is there a way to work the struct hack or some similar solution in Arduino to like achieve the first example?
The size of the struct must be known at compilation time. Const data types in structs can change per instance of the structure, that is why you are getting the invalid use of non-static data member 'Alarms::num_of_reads' when you try to initialize your array. The best way to solve this is to have an init_alarm and destroy_alarm functions. Like so ...
#include <stdio.h>
#include <stdlib.h>
#define DEFAULT_NUM_OF_READS (24)
struct alarm {
// Configurable parameters
const int number_of_reads;
// State variables
int *reads;
};
void init_alarm(struct alarm *alarm)
{
alarm->reads = (int *) malloc(alarm->number_of_reads * sizeof(int));
}
void destroy_alarm(struct alarm *alarm)
{
free(alarm->reads);
}
int main(int argc, char **argv)
{
// When we create our struct, set number_of_reads to default
struct alarm alarm = {.number_of_reads = DEFAULT_NUM_OF_READS, .reads = NULL};
init_alarm(&alarm);
alarm.reads[0] = 13;
alarm.reads[23] = 100;
printf("alarm.reads[0] = %d, alarm.reads[23] = %d\n", alarm.reads[0], alarm.reads[23]);
destroy_alarm(&alarm);
return 0;
}
Note: Inorder to use the designated initializer to initialize a structure you must compile with ANSI (C99) like so ...
gcc --std=c99 test.c -o test

Having a struct declaration as the function parameter in VC++

I'm using asn1c to generate C++ encoder/decoder codes. There is a problem in the generated code (which is a huge code) preventing it from compile on VC++ which I try to make it simple here:
There is A_SET_OF macro in the generated code defined as:
#define A_SET_OF(type) \
struct { \
type **array; \
int count; /* Meaningful size */ \
int size; /* Allocated size */ \
void (*free)(type *); \
}
This macro is later used in several parts of code. For instance:
A_SET_OF(struct MyStructure {
long myNumber;
char* myPointer;
} ) myList;
I get a C2226: syntax error : unexpected type error on these parts. To find what actually is causing the problem, I substituted the actual macro definition:
struct {
struct MyStructure { long myNumber; char* myPointer; } **array;
int count; /* Meaningful size */
int size; /* Allocated size */
void (*free)(struct MyStructure { long myNumber; char* myPointer; } *);
} myList;
The error is caused by the void(*free) line. Apparently, having struct declaration as a function parameter is a non-standard feature which VC++ do not support (and gcc probably supports as asn1c primary targets Linux).
I am looking for a workaround to this issue, preferably fixing the A_SET_OF macro definition as there are many references to it. typedefing the struct passed to free function might solve this issue but I am not sure how it could be done for these anonymous structures.

Corrupted vector entries with LPCWSTR vector

I ahve the following piece of code. I get a correctly filled vector. But I am unable to print or use the vector contents which are file names from a directory. As soon as I do enter the first iteration. Everything gets lost. What am I doing wrong?
wprintf - This works OK
wcout-- here is where everything ends up corrupted
#include <windows.h>
#include <sstream>
#include <string>
#include <vector>
#include<iostream>
void GetAllFiles(vector<LPCWSTR>&, wstring);
using namespace std;
void main (void)
{
vector<LPCWSTR> files(0);
wstring path = L"Datasets\\Persons\\";
wstring ext = L"*.*";
wstring fullPath = path+ext;
GetAllFiles(files,fullPath);
for (unsigned i=0; i<files.size() ; i++)
{
try
{
wcout<<"::\n"<<files[i];
}
catch(exception &ex)
{
cout<<"Error:"<<ex.what();
}
}
}
void GetAllFiles(vector<LPCWSTR>& fileNames,wstring dir)
{
WIN32_FIND_DATA search_data;
memset(&search_data, 0, sizeof(WIN32_FIND_DATA));
HANDLE handle = FindFirstFile(dir.c_str(),&search_data);
while(handle != INVALID_HANDLE_VALUE)
{
wprintf(L"Found file: %s\r\n", search_data.cFileName);
fileNames.push_back(search_data.cFileName);
if(FindNextFile(handle, &search_data) == FALSE)
break;
}
}
I have attached a screen shots of the output.
search_data.cFileName is a pointer to memory controlled by the FindFirstFile/FindNextFile iterator interface; you cannot store this pointer value as the pointed-to memory could change from iteration to iteration (or even be freed after the iteration completes).
Instead, you must make a copy of the string to put in your vector, e.g. using wcsdup. Even better, define your vector as a vector<wstring>, so that push_back(search_data.cFileName); creates a wstring with the contents of search_data.cFileName.
Probably that's happening because you pass local variable to push_back(). I'm not sure here, but what could happen here:
push_back expects object of type LPCWSTR, while you passing char* instead. I don't know, how this conversion is done, but probably the pointer is just copied, and the value of this pointer becomes invalid whenyou return from the function - try explicit copying the strings before passing them to push_back.

addition and subtraction problems in c++

If after addition, you have to divide by the third number, you need more than 3 variables. Why is that?
can anyone please help me with this problem. it will be very grateful.why do we need to after addition, you have to divide by the third number, you need more than 3 variables. Why is that?
thank you
#include <stdio.h>
class res
{
int a[6],i;
public:
int result()
{
for(i=0;i<3;i++)
{
if(a[i]%3==0)
{
"sum=sum+a[i]";
}
}
}
}; // Added newly
int main()
{
res r;
int i,a[5];
cout<<"enter three numbers";
for(i=0;i<3;i++)
{
cin>>a[i]);
}
r.result();
return 0;
}
First you need to understand that the array variable in main is different from the class member a. And in result method, class variable a is not initialized with valid values to do a % operation on it.
if(a[i]%3==0)
{
"sum=sum+a[i]"; // And probably here you meant sum=sum+a[i];
// string should be enclosed in double quotes.
}
With the above modification made, class res doesn't know what the variable sum is.
Given the number of many other mistakes in your program, I suggest you to read a book from the suggested link.

Resources