I'm using these code to receive string from uart then matching them with this enum then putting them on switch-case.
char temp[3],rx_buf[100];
enum form {
GGA = 1,
GSA
};
enum form gnssform ;
sprintf(temp,"%c%c%c",rx_buf[3],rx_buf[4],rx_buf[5]);
gnssform=temp;
I can't understand that we can directly use something like EXAMPLE:
gnssform=GSA;
and there is no error ,but this:
gnssform=temp;
not compiling .and please tell me the possible way to do this???,because of this EXAMPLE I believe that it must be possible.
the error is :
a value of type "char *" cannot be assigned to an entity of type "enum form"
please do not tell me to use if-else because I hate that.
Finally I used
if(rx_buf[3]=='G'&&rx_buf[4]=='G'&&rx_buf[5]=='A')gnssform=GGA;
else if(rx_buf[3]=='G'&&rx_buf[4]=='S'&&rx_buf[5]=='A')gnssform=GSA;
There's no built-in solution. Easiest way is with an array of char* where the enum's int value indexes to a string containing the descriptive name of that enum.
enum FRUIT_ENUM {
apple, orange, grape, banana,
};
static const char *FRUIT_STRING[] = {
"apple", "orange", "grape", "banana",
};
Then you can do something like below in a loop.
if (!strcmp(FRUIT_STRING[n],temp))
gnssform=n;
GSA is a constant value of enum form.
temp is a char pointer to the three letters 'GSA'.
They are not the same thing, and you cannot directly assign them.
Related
If I have a bunch of error codes in my application header.h like:
enum errors {
ERROR_NONE,
ERROR_TOTO,
ERROR_TATA,
ERROR_TUTU,
ERROR_MAX,
};
Should I define the string associated with each code in the header like this:
static const char * const errors_strings[ERROR_MAX] = {
"ERROR_NONE",
"Something happened with toto",
"Tata is wrong",
"Pasta or pizza?",
};
or directly in the printing function:
void print_error(int error)
{
char* array[ERROR_MAX] = {
"ERROR_NONE",
"Something happened with toto",
"Tata is wrong",
"Pasta or pizza?"
};
printf("%s\n", errors_strings[error]);
}
Which is the better practice?
First of all, make the error enum a named type with typedef. Ideally we shouldn't mix int and enum types but treat enum as distinct types, even though the weak type system in C doesn't provide much help there. (However, check out How to create type safe enums? for some tips & tricks.)
As for if you should have the string table outside a function or inside one, it entirely depends on if one or several functions are using it. If only one function is using it, then it's a good idea to place the table inside it, to reduce its scope.
Also since the string array has size ERROR_MAX it cannot hold more initialized items than that, but nothing prevents it from having less. Therefore to guarantee integrity between the enum and the table, always do this:
static const char * const errors_strings[] = { ... }; // no size specified
_Static_assert(sizeof errors_strings / sizeof *errors_strings == ERROR_MAX,
"helpful error message here");
I have a struct that looks like this:
struct persons_s
{
size_t count;
char names[MAX_PERSON_COUNT][MAX_PERSON_NAME_LENGTH];
};
When I try to assign values like this, it does not work:
struct persons_s persons;
persons.count = 2;
persons.names = { "test1", "test2" };
But this works:
struct persons_s persons = { 2, { "test1", "test2" } };
I am assuming this has something to do with the names array being constant, but I'm not sure.
So I'm asking:
What is the exact reason the first way does not work?
Is there a better way to accomplish this?
I also tried
char *names[MAX_PERSONS_COUNT];
but this doesn't work either because I have to use it with strcpy (as destination, strcpy(persons.names[i], source);).
Currently I am doing the assignment like this (using the first struct):
struct persons_s persons;
persons.count = 2;
strcpy(persons.names[0], "test1");
strcpy(persons.names[1], "test2");
You are trying to assign a constant to a pointer (char[][], or **char), in C a string is an array of chars, you can either use strcpy or make it yourself with a for loop.
Your way strcpy(persons.names[0], "test1"); works fine and is probably the best option for you.
So I'm trying to utilize Enumerated types in C for the first time. So I have an Enumerated "variable?" declared and I also have a struct which has a variable of the Enumerated type(among other things). Finally I have a static array for which there is an element containing each of the enum "types?" in the same order they were declared. I am hoping to use the enum type to act as an index for the array.
So my problem is that I need to somehow relate a char* variable to the enumerated type. If I KNOW that the Char* variable is one of the enum types, is there some way to assert that without having to look at each char to determine which specific enum"option" it is?
Example:
enum example = {abc,def}
struct _strExample {
enum example letters;
....
};
typedef struct _strExample strEx;
static strEx Table[2] = {
{abc,...}
{def,...}
};
//Given char* "abc" , want either example.abc or 0 ( correct index of table)
So given the char* "abc"(does not need to be char*), is there a simple way to get either the correct enum "type?"(abc or def)or the correct index of the table? I know that I could check all the individual chars in the char* and manually determine which enumerated "type?" it is, but I am going to be working with a very large set of enumerated variables and this kind of thing is exactly what I was trying to avoid. any help or advice you guys could give on enumerated types and/or my design would be most appreciated.
Use a an array of strings where the index into the array is the enum value. If the strings are all short, or all about the same length, storing the string in the array makes sense. Otherwise, use a char* pointer.
typedef enum enum_t { plugh, plover, xyzzy, y0 } enum_t;
const char *etable = { "plugh", "plover", "xyxxy", "y0", NULL };
With that, you can convert with a simple search like:
enum_t find_enum(char *sval)
{
enum_t result=plugh; /* value corresponding to etable[0] */
int i=0;
for (i=0; etable[i]!=NULL; ++i, ++result)
if (0==strcmp(sval, etable[i])) return result;
return -1;
}
The enum-to-string converstion is simply etable[e-plugh]. Those allow for a different definition of enum_t where the first meaningful value may not be 0, but the values are sequentially assigned thereafter.
No, you can't lookup any scalar value from a character array. You have to iterate over a set of strings to compare and find the relation to the enum member.
You can use an array of structs
typedef struct { int value; const char * name; } lookup_t;
lookup_t lookup[] = {
{ 1, "One"},
{ 0, NULL} // end tag, alternatively use the _countof(lookup) to get the number of elements
};
and compare your char* with the name member. Then you use the value on match.
Use if :
char *ex = "abc";
strEx strex;
if(!(strcmp("abc",ex))) {
strex.letters = abc;
}
else {
strex.letters = def;
}
I am working on a simple filesystem, which (obviously) contains folders, files, etc.
A (simplified version of a) folder is represented by a structure while in RAM like so:
typedef struct{
char label[20];
unsigned int id;
t_node contents[50];
} folder;
Now, i obviously want label to contain the raw byte string with in it the name (even better would be the raw string without trailing 0, but that's a sacrifice I am willing to make).
No,here's how I create and use a struct:
folder* myFolder = (folder *) malloc(sizeof(folder));
myFolder->label = "name";
//Which doesn't work, if I try this:
char name[20] = "name";
myFolder->label = name;
//this too, doesn't work.
The error message says "incompatible types when assigning to type ‘char[20]’ from type ‘char *’".
Which I understand, but don't know how to resolve.
Thanks in advance
Use strncpy():
char name[20] = "name";
strncpy(myFolder->label, name, sizeof(myFolder->label) - 1);
myFolder->label[sizeof(myFolder->label) - 1] = 0;
Try using strncpy():
strncpy( myFolder->label, "name", 20 );
instead of
myFolder->label = "name";
You cannot use the assignment operator to fill the array, in this case the right hand side of "name" will resolve to a char pointer.
Also I would suggest replacing the constant 20 with some defined constant indicating what the value is (ie MAX_FOLDER_LABEL_LEN).
You need to use strcpy
strcpy(myFolder->label, "name");
An array is not a modifiable lvalue, so you can't assign a value to it. You have several solutions:
declares label as pointer to char;
use strcpy (or equivalent).
Perhaps this bridge likely has been crossed many times and in many ways... reading a simple text .conf file and acting upon its entries.
In my case, the file format is simple.. a series of tokens and assignments, as in:
token_name_1 value
with a tab character as the field delimiter and a unix line-ending for each the record.
The .conf file directly alters certain program configurations, all of them stored in a single structure. Variables of types Integer, float, char[], and *char are represented in the structure.
A quick but boring approach involves, for example:
if (strcasecmp(token,"token_name_1")==0)
token_name_1=value;
But I determined that it would be sweet to do the deed in a nice tight loop. In C.
So it seemed best to construct an array which provides pointers to each of the structure variables I wish to expose; another that provides the name of the variable; and a third which describes the stored data type and a desired default value.
These look like this:
const char* allowed_tokens[] =
{
"loglevel",
"debugecho",
"errorSqlDisable",
"ClearErrorDbOnExit",
"\0" // terminates list
}
int *varpointers[] =
{
&appinfo.nLogLevel,
&appinfo.debugEcho,
&appinfo.OWFSLogLevel,
&appinfo.OWFSLogEchoToDisplay,
0 // terminates list
};
char *varDatatypes_defaults[] =
{
"I|6", // for LOG_INFO
"B|false",
"I|0",
"B|true",
"\0" // terminates list
};
The loop looks like this (pseudocode):
row=0;
while (read a line of the .conf file into cLine)
{
get the token_name and value from cLine
check if allowed_tokens[row]==0 and if true, exit the loop
// example cLine= "debugecho false"
find match to "debugecho" in allowed_tokens. This provides an offset into varpointers and varDatatypes.
get the default data type and default value tokens from varDattypes_defaults[row]
Do the assignment. For example, if the data type=="I":
*varpointers[row]=atoi(value);
++row;
}
This technique works fine, but there are two problems.
It would be preferable to combine the three arrays into a single array. Is there a best practice here?
The array of pointers (varpointers[]) is defined as *int. I did so as I want it to hold pointers. However if the variable pointed to is not an integer data type, warning: initialization from incompatible pointer type is triggered. Of course, char * and int * cannot be mixed... so how otherwise could this be done such that a single pointer array is used?
I realize I can do all this in c++. This luxury is not an option at this point.
You can combine them into one array by structs, e.g.
typedef struct { char *token; void *var; char *defaults; } the_type;
the_type the_data[] = { { "loglevel", (void*)&appinfo.nLogLevel, "I|6" },
{ "debugecho", (void*)&appinfo.debugEcho, "B|false" },
...
};
The generic pointer type is void *. Your code has to ensure you use the correct type when actually writing to the variable being pointed to, e.g. *(int*)the_data[0] = 42;.
I would use an enumeration to specify the types so you don't have to parse a string. The values could be stored in an union.
typedef enum {
BOOLEAN,
INTEGER,
} type_t;
typedef union value {
bool boolean;
int integer;
} value_t;
typedef struct token {
char *name;
type_t type;
value_t value;
} token_t;
Now you can define your defaults like so:
token_t data[] = {
{ "loglevel", INTEGER, { 6 } },
{ "debugecho", BOOLEAN, { false } },
{ "errorSqlDisable", INTEGER, { 0 } },
{ "ClearErrorDbOnExit", BOOLEAN, { true } },
{ 0 }
};
This will get pretty cumbersome if the number of configuration keys gets large. You might want to think about storing the configuration in a hash table or a tree.
Here is a short example that seems to accomplish what you want.
If we are talking about the same data type, use double pointers (you get an array of arrays)
Declare a struct holding your pointers, then use a pointer to your struct to work on.
For declaring a general pointer, you can use void instead of int. But then every time you have to cast the pointer to use it properly.