This question already has answers here:
Easy way to use variables of enum types as string in C?
(20 answers)
Closed 6 years ago.
gcc 4.4.2 c89
I have the following enum:
enum drop_options_e
{
drop_ssm,
drop_snm,
drop_ssb
};
I am just wondering that is the best way to get the string representation value from the enum.
So basically, instead of returning the value of 0 for drop_ssm, I could get the 'drop_ssm' instead.
Many thanks for any advice,
One way is to do like this:
enum drop_options_e
{
drop_ssm = 0,
drop_snm ,
drop_ssb ,
LAST_ENTRY /* Should be last entry */
};
const char* drop_options_s[LAST_ENTRY] = {"drop_ssm", "drop_snm", "drop_ssb"};
when you want a string representation of an enum you can drop_options_s[enum];
Using X-Macro technique:
file items:
ITEM(drop_ssm)
ITEM(drop_snm)
ITEM(drop_ssb)
source:
#define ITEM(A) A,
enum drop_options_e
{
#include "items"
last
};
#undef ITEMS
#define ITEM(A) #A,
char item_names[] = {
#include "items"
NULL};
So now item_names[drop_ssm] will give you text string "drop_ssm"
C has no support for that. You will have to have a switch or equivalent somewhere.
If you have a compiler that supports C99's designated initialisers, you can improve upon Naveen's answer:
enum drop_options_e
{
drop_ssm,
drop_snm,
drop_ssb
};
#define ENUM_TO_S(e) [e] = #e
const char *drop_options_s[] = {
ENUM_TO_S(drop_ssm),
ENUM_TO_S(drop_snm),
ENUM_TO_S(drop_ssb)
};
(With this method, you don't have to worry about the array initialisers being in the same order as the enum values).
There's nothing out of the box. You can do some very interesting things with macros and Boost.Preprocessor, but it's quite involved, and I'm not sure how well it would work in C; I've done things in C++ that let me write, e.g.:
ENUM(
ColorComponent,
(red)
(green)
(blue)
(alpha)
);
// ...
ColorComponent cc = ColorComponent_red;
std::cout << "Color: " << toString(cc) << "\n";
The best way I have see to handle this is to create a translation array. Something like:
struct {
enum drop_options_e value;
char *string;
} TranslationArray[] = {
drop_ssm, "drop_ssm",
drop_snm, "drop_snm",
drop_ssb, "drop_ssb",
};
This can be problematic if you're enum is quite large.
I've so liked all answers here! During trying them I've found something very short and nice with BOOST_PP_STRINGIZE macro from boost:
//Define the enum you need
typedef enum
{
INTEGER = 0,
STRING = 1,
BOOLEAN = 2,
}eValueType;
// Then in code use BOOST_PP_STRINGIZE, for example:
char* valueTypeStr = BOOST_PP_STRINGIZE(INTEGER);
Related
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.
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 could be going about this all wrong, and it could be that an enum does is not a good way to solve this problem, but I am really not sure where to go with it otherwise.
Basically, I have non-sequential codes that correspond to certain strings. For example,
9 = "Enter"
10 = "Right"
15 = "Left"
17 = "Down"
And so on. I currently have this implemented with a large set of definitions:
#define ENTER_INDEX 0
#define RIGHT_INDEX 1
That is used to index into a char* array:
char* array[] = { "Enter", "Right" };
And when I receive information regarding which code was received, I then print the strings with a huge switch-case.
Any ideas on how to do this more efficiently? Is an enum a good approach?
Sure, you can use an enum, but that won't help you associate the names with the numerical values.
The problem is that you can't declare an enum and a string "in parallel" from the same source code characters, without using trickery such as X macros. Even then you probably won't solve the requirement for different casing which your code shows. Which you might want to avoid, because obfuscation.
The enum would be just:
typedef enum {
ID_ENTER = 9,
ID_RIGHT = 10,
ID_LEFT = 15,
ID_DOWN = 17
} Id;
I would then use C99's fantastic support for explicit indexes in array initializers to declare an array of strings indexed by an Id:
static const char *id_names[] = {
[ID_ENTER] = "Enter",
[ID_RIGHT] = "Right",
/* add more */
};
Note that the above is independent of the order, since each element initializer has an explicit index. This makes it very robust.
You can of course use a macro to cut down on the repetition, but that will make an all-caps string array:
#define DECL_ID(i) [ID_ ## i] = #i
static const char *id_names2[] = {
DECL_ID(ENTER), DECL_ID(RIGHT), /* add more */
};
To implement an enum with specific values for its members can be done by
enum options_en
{
Enter=9,
Right=10,
Left=15,
Down=17,
Default=0;
} ;
then you can declare a variable which can take only values defined in the enumerated type
options_en opt_val = Default;
For exploring more information about your question , refer this link, Found it very useful and is relevent to your question
http://www.cprogramming.com/tutorial/enum.html
A dictionary or hash table can be used. In c++ stl libraries I don't recall the name of the collection but in short y. use dictionaries/hashtables with generics.
So in your case you fill up the dictionary with key value pairs and when your later use the collection you can get a value using your key.
So it gets rid of switch statements and enums and will allow you to map any two types. Here is pseudo code
Value = dictionary[key]
So if key is 0 then the value will be set to Enter based on your example.
In short lookup examples for c++ and dictionary as I am answering from mobile phone and could not direct you to the exact collection name.
You can also create a map during initialization:
#include<stdio.h>
typedef struct { int code; const char *str; } key_info;
key_info keys[] = {
{9, "Enter"}, {10, "Right"}, {15, "Left"}, {-1, NULL}
};
#define MAX_KEY_CODE 15
size_t keymap[MAX_KEY_CODE + 1];
int main ( ) {
size_t i;
for (i = 0; keys[i].str; i++) {
keymap[keys[i].code] = i;
}
printf("%s\n", keys[keymap[10]].str);
return 0;
}
A huge switch is not a bad solution. The question is why do you need an extra array of names. Why don't you return directly string literals from the switch?
char *name(int code) {
switch (code) {
case 9: return("Enter");
case 10: return("Right");
case 15: return("Left");
...
}
}
I have an enum like that:
enum {
ID_FOO = 0,
ID_BAR,
ID_BAZ
}
And a constant array using designated initializers like hat:
char* arr[] = {
[ID_FOO] = "foo stuff",
[ID_BAR] = "bar stuff",
[ID_BAZ] = "baz stuff",
0
}
Now when I add a value to the enum, e.g. after ID_FOO but forget to add it to the array, then I would get an uninitialized null-initialized 'hole' in the array. Is there any way to prevent that, or at least get a warning from the compiler?
A non-portable GCC-only solution is fine.
One way is to add a sentinel maximum value to your enum, which you can use to verify that this maximum value is the same as the number of elements in the array.
enum {
ID_FOO = 0,
ID_BAR,
ID_BAZ,
// insert new values here
ID_MAX
}
assert(ID_MAX == (sizeof(arr)/sizeof(arr[0]) - 1));
This is a runtime check; have a look at C compiler asserts - how to implement? for ideas on how to get a compile-time error instead.
you can use X-Macros to keep them in sync, although some may argue about the prettiness of the resulting code.
The idea is to take all the information you need for both structures and put it into a single macro:
entries.inc
ENTRY(ID_FOO, "foo stuff")
ENTRY(ID_BAR, "bar stuff")
ENTRY(ID_BAZ, "baz stuff")
And then later, redefine your macro such that for each structure you need to build, you pull out the appropriate part from your data:
foo.c
/* here define what entry should be for your enums */
#define ENTRY(id, name) id,
enum {
#include "entries.inc"
};
/* and then redefine for the char array and include again */
#undef ENTRY
#define ENTRY(id, name) [id] = name,
char* arr[] = {
#include "entries.inc"
0
};
int main(int argc, char* argv[]) {
/* whatever */
}
I have a struct like this:
typedef struct string {
unsigned long length;
unsigned *data;
} string;
Can I write something so that when I do this:
string s;
the length property is zero, instead of whatever happens to be in the memory? data works well, as it's preset to zero or a null pointer.
Example of what happens right now:
string s;
printf("length: %lu\n", s.length);
printf("pointer: %lu\n", (unsigned long) s.data);
Result:
length: 140737488347584
pointer: 0
I want to avoid having to call an initialisation function on each new string just to set length to zero.
More information
Now that I think about it, it may not be really necessary to do this in my particular case (though it would be nice) because most people would initially set the string through ctou (which imports UTF-8 from char pointer) and that function sets length to zero anyway.
You could use
string s = {0,NULL};
To combine the two previous answers (sort of) I'd define something like
#define STRING_INITIALIZER {0, NULL}
.
.
string s = STRING_INITIALIZER;
BTW, your struct declaration itself looks weird for a string. Either this is not a string as we usually understand it in C but merely a dynamic array of unsigned, or it is really a string and then this should be char*.
The accepted answer answered the question that you asked, but didn't address whether you ought.
Your string is a class and has class semantics. The initializer may be fine for kernel code where every last instruction counts, but in application code your static initializers are ugly and error prone.
It is possible to write classes in C, the stdio FILE type is a fabulous example, and here is the same idea applied to your string class:
typedef struct {
int length;
char *data;
} String;
String *sopen() {
String *s = malloc(sizeof(String));
if(s) {
s->length = 0;
s->data = NULL;
}
return s;
}
int sclose(String *s) {
free(s->data);
free(s);
return 0;
}
int main()
{
String *s = sopen();
return sclose(s);
}
Where I've followed the FILE* function name style for metaphoric reasons. Yep, there's more code. Yep, you have to explicitly deallocate the structure; but note that even though you were counting on auto class initialization in your code sample, if data was ever allocated, you couldn't count on leaving scope to automatically deallocate the storage for you.
This approach also has the merit of abstracting the type of data from the users of the class. As there seems to be some confusion about what type you really want to use, this flexibility may come in handy.
#define DEFINE_STRING(s) string s = {0, NULL}
{
DEFINE_STRING(s);
}
You can use a macro to "do this automatically"