How to implement an enum with specific values for its members? - c

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");
...
}
}

Related

Comparing Char* to Enum variable in C

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;
}

How to change a variable whose name is the user input?

For example, I have this block:
int nFirst, nSecond;
char sInput[10];
printf("Which variable to change to 10?");
scanf("%s", &sInput);
// BAD - inflexible and unmaintainable
if(strcmp(sInput,"nFirst") ==0){
nFirst = 10;
}
else if (strcmp(sInput,"nSecond")==0) {
nSecond =10;
}
Is there a nice way to do this? like treat a string as if its a variable name?
No, there is no "nice" way of doing this in C. Variable names (typically) aren't preserved in the generated machine code, except to support debugging. C doesn't have a built-in mechanism for translating a string value into a reference to a variable of the same name.
You would have to map variable names to variables manually. You could build a lookup table, associating a string value with the address of the corresponding variable:
struct vn {
char *varname;
void *addr;
Typeinfo t;
};
where Typeinfo is some enumeration or other mechanism for encoding the type of the variable, giving you something to the effect of
int foo;
double bar;
char *blurga;
struct vn varsByName[] = { {"foo", &foo, IntType},
{"bar", &bar, DoubleType},
{"blurga", blurga, CharPtrType} };
I don't recommend doing this.
Another, platform-dependent approach is to put all your variables into a shared library and then have access to them by names. Have a look at dlsym/dlopen functions.
void* handle = dlopen("mysymbols.so", RTLD_LOCAL | RTLD_LAZY);
int* var = (int*) dlsym(handle, user_typed_name);
*var = 10; /* modify the variable */
You could implement something like a dictionary or a two-dimensional array which contains the "variable name" and the value. Then this comes down to setting an array element to a new value.
Other than that: C# and other object oriented languages would allow this through reflection, but as C itself isn't object oriented, you can not do that (C++ support for this seems to be very limited).
You can do it with a macro:
#define MAYBESET(name) if (strcmp(sInput, #name) ==0 ){ name = 10; }
#name is the real value of name changed to a string literal.
For a small number of variables then your algorithm should perform well. If there are many variables that could be changed, rather than just two, then another algorithm should be considered. Making this pretty and clear isn't exactly easy in C.
If you really wanted this to be faster you could either do a hash table or use a switch/case like:
int First, Second; // Note that I got rid of your leading n
char sInput[10];
printf("Which variable to change to 10?");
scanf("%s", &sInput);
// BAD - inflexible and unmaintainable
// referring to character array overflow potential, I assume
switch (sInput[0])
{
case 'F':
if (0 == strcmp("irst", sInput+1) )
{
First = 10;
} else
{
// error
}
break;
case 'S':
if (0 == strcmp("econd", sInput+1) )
{
Second = 10;
} else
{
// error
}
break;
default:
// error
break;
}
If you don't like the way that this looks then you could use macros (#define) to make it less big looking, but it would turn out the same. Another option that you could employ would be to write a small program that output the source code of this program which would handle all of the repetitive and tedious parts.
Another way to do this, if all of the variables are of the same type, would be to create an array of them and input their index in rather than a name, but then you have to add code to check against inputting an index out of range of the size of the array.

Avoiding null-initialized holes when using designated initializers

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 */
}

string representation of enum values [duplicate]

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);

Referring to data both by name and by number in C

I have twenty or so integers which I want to be able to refer to by name when they're being set, but I would like to also be able refer to them by number like they were in an array, so I can print them out one by one using a for loop. Any ideas how to code this in C? Here's what I'm talking about in pseudo code:
/* a data structure to keep a count of each make of car I own */
my_cars;
/* set the counts */
my_cars.saabs = 2;
my_cars.hondas = 3;
my_cars.porsches = 0;
/* print the counts */
for(all i in my_cars) {
print my_cars[i];
}
Is this asking too much of a low level language like C?
struct car {
const char *name;
int count;
} my_cars[] = {{"Saab", 2}, {"Honda", 3}, {"Porsche", 0}};
int i;
for (i = 0; i < sizeof(my_cars) / sizeof(my_cars[0]); i++)
printf("%s: %d\n", my_cars[i].name, my_cars[i].count);
To do that you should use an array instead of standalone data fields
#include <stdio.h>
typedef enum CarType {
CART_SAAB,
CART_HONDA,
CART_PORSHE,
CART_COUNT_
} CarType;
typedef struct MyCars {
unsigned ncars[CART_COUNT_];
} MyCars;
int main(void)
{
MyCars my_cars = { 0 } ;
unsigned i;
my_cars.ncars[CART_SAAB] = 2;
my_cars.ncars[CART_HONDA] = 3;
for (i = 0; i < CART_COUNT_; ++i)
printf("%u\n", my_cars.ncars[i]);
return 0;
}
C can do anything any other language can do. This does look like homework and I bet you are expected to make something with a key. Remember, your instructor wants you to use the data structures he or she is trying to teach you. He doesn't really want the problem solved in any random way, he wants it solved applying the topics you have been discussing.
So think about a data structure containing both strings and counts, one that can be searched, and provide functions to do that. What you are likely to get here are nice, professional, simple solutions to the problem. And that's not really what your instructor wants...
enum Makes { SAAB, HONDA, PORSCHE, INVALID };
int my_cars[INVALID];
my_cars[SAAB] = 2;
my_cars[HONDAS] = 3;
my_cars[PORSCHE] = 0;
You need two data structures. An array to hold the numbers, and a map from the name to the index in the array. In C++ you'd use one of the map classes in the standard library. I don't know what's available in C but I'm sure there are map implementations available.
The low-level C way to do this would be to wrap the cars structure into a union:
// define a structure for the cars.
typedef struct
{
int saabs;
int hondas;
int porsches;
} cars;
// wrap it into a union:
typedef union
{
cars byname;
int byid[3]; // Note: Number and type must match with the cars structure.
} cars2;
int main (int argc, char **arg)
{
cars2 my_cars;
int i;
// fill out by name:
my_cars.byname.saabs = 1;
my_cars.byname.hondas = 5;
my_cars.byname.porsches = 3;
// print by index:
for (i=0; i<3; i++)
printf ("%d\n", my_cars.byid[i]);
}
Umm...based on what you've pseudo coded up there you could probably use a union. The answers others are giving seem oriented around allowing a mapping between names and numbers. If thats what you're looking for (as in, being able to print the names) then their answers will be better. However it sounds like to me you're simply looking for clarity in the code to allow you to reference things by name or number, in this case a union would be ideal I think. This is exactly the type of thing a low level language like C lets you do.
union my_cars {
struct names {
int saab;
int ford;
...
}
int[NUM_MAKES] nums;
}
You will have to be careful to ensure NUM_MAKES is in sync with the number of makes you define. Then you can do something like:
my_cars.names.saab = 20;
my_cars.nums[0] = 30;
And modify the same element.
FYI, my C is a little rusty so there may be syntax errors there, feel free to correct.
EDIT:
Ahh, I read some of the other answers using ENUMs or DEFINEs and those might actually be simpler/easier than this one...but unions are still worth knowing.
There are maybe a couple of options.
It is possible to have the same space in memory defined (and used) in two different ways. In other words, you could have a struct with the named members and reference it either as the struct or as an array depending on how you intended to address it.
Alternatively, you could do an enumerated typedef that names the locations in the array, e.g.
typedef enum {
SABS = 0,
HONDAS,
PORSCHES
} cars;
This would then allow you to refer to offsets in the array by name, e.g.
mycars[SABS] = 5;

Resources