How do you convert values to enumeration constants in c? - c

Earlier I was fixing a lexer for my parser; now I have to create a validater for it. My idea was to convert the enumeration constants to strings by using the following preprocessor macro: #define MACRO_STRINGIFY(x) #x.
Then I made a function to compare various token values lactually, I made three, but they are all the same with a few minor changes):
unsigned int compare_keyword( enum script_keywords keyword, char *token ) {
char *temporary = MACRO_STRINGIFY( keyword );
unsigned int i = 0;
for (; i < (strlen( "KEYWORD_" ) + 1); i++) {
++temporary;
}
// 0 on match, 1 on no match
return strcmp( temporary, token ) ? 1 : 0;
}
Now, this function works absolutely fine... when keyword is the enumeration constant:
void test() {
printf( "\nIF is " );
// Finish the sentence based on the return value
compare_keyword( KEYWORD_IF, "IF" ) ? printf( "not a keyword.\n" ) : printf( "a keyword.\n" );
}
test(); //--> Outputs 'IF is a keyword' like expected.
On the other hand, the function does not work as intended if I pass a value like 1 (the value which the symbolic enumeration constant KEYWORD_IF resolves to.):
// Same as last time with one edit:
void test() {
/* See above code with following change on line 4 */
compare_keyword( 1, "IF" ) /* etc... */
/* Rest of code from previous test */
}
test(); //--> Outputs 'IF is not a keyword' even if KEYWORD_IF resolves to the value 1.
The point I'm getting across here is that the preproccessor is very literal, and I would much prefer using a for loop to loop through the constants efficiently without bloating the code size (which is what would happen if I end up using enumeration constants). Therefore, the question is how can I convert plain integer values to their symbolic names without using switch…case… or if…else…?
Edit: Enumeration Details:
enum script_keywords {
KEYWORD_IF = 1,
KEYWORD_THEN = 2,
KEYWORD_ELSEIF = 3,
KEYWORD_ELSE = 4,
KEYWORD_ENDIF = 5,
KEYWORD_FOR = 6,
KEYWORD_TO = 7,
KEYWORD_STEP = 8,
KEYWORD_EXITFOR = 9,
KEYWORD_NEXT = 10,
KEYWORD_LOOP = 11,
KEYWORD_WHILE = 12,
KEYWORD_EXITLOOP = 13,
KEYWORD_ENDLOOP = 14,
KEYWORD_DO = 15,
KEYWORD_EXITDO = 16,
KEYWORD_UNTIL = 17,
KEYWORD_ON = 18,
KEYWORD_GOTO = 19,
KEYWORD_CALL = 20,
KEYWORD_LET = 21,
KEYWORD_DIM = 22,
KEYWORD_AS = 23
};

The Macro "MACRO_STRINGIFY" is evaluated at compile time by the preprocessor. It will return the actual name of the argument, so
MACRO_STRINGIFY(keyword) -> "keyword"
MACRO_STRINGIFY(KEYWORD_IF) -> "KEYWORD_IF"
MACRO_STRINGIFY(1) -> "1"
Apparently this will not lead to any solution.
Instead one could use a compile-time generated key-value mapping to implement such functionality:
struct map
{
int key;
const char* value;
};
struct map mappings[] =
{
{ KEYWORD_IF, "IF" },
{ KEYWORD_ELSE, "ELSE" }
};
and then simply iterate those mapping entries at runtime to find out what you need:
static int is_keyword(const char* str)
{
int i;
const int count = sizeof(mappings) / sizeof(mappings[0]);
for(i = 0; i < count; i++)
{
struct map* m = &mappings[i];
if(strcmp(str, m->value) == 0)
{
return 1;
}
}
return 0;
}
void test()
{
const char* str = "IF";
const char* what;
if(is_keyword(str))
{
what = "a keyword";
}
else
{
what = "not a keyword";
}
printf("%s is %s.\n", str, what);
}
This is about as minimal as it may get. The executable binary does not normally include names of enumeration values as known from e.g. Java.
To extend this even further, you could do some preprocessor voodoo to generate the mapping array (semi-) automatically. But as I am not a big friend of preprocessor voodoo I will skip that ;)

Related

Mapping string to enum value

In my program, I have an enum that is used for indexing my array members. The reason is that it is much easier for me to understand which parameter I am accessing without knowing its index in the array
enum param_enum
{
AA,
AB,
AC,
AD,
PARAM_COUNT
};
static int16_t parameters[PARAM_COUNT] =
{
[AA] = 5,
[AB] = 3,
[AC] = 4,
[AD] = 8,
};
I can then access any parameter for example:
parameters[AA] = 10; // Update AA parameter to value 10.
I will be receiving serial commands such as :
"AA:15"
When I receive this command, I must determine what parameter I need to modify based on the first 2 characters, then skip the 3rd character( because it is just ":" and I dont care about it) and the remaining characters will show the new value)
I wonder if there is any easier way to map the enum to a string
My current method:
// line holds the string data
// cmd_size is the length of string data
bool parse_command(char *line, uint16_t cmd_size)
{
printf("data size = %u \n",cmd_size);
char temp_buf[3] = {0};
temp_buf[0] = line[0];
temp_buf[1] = line[1];
printf("temp_buf = %s \n",temp_buf);
if (!strcmp("aa", temp_buf))
{
printf("aa: detected \n");
char temp_storage[5];
int16_t final_value;
for(int i = 3;i<=cmd_size; i++){
temp_storage[i-3]=line[i]; // read data and append to temp bufferfrom the 3rd character till the end of line
if(line[i] == 0){
printf("null termination triggered \n");
final_value = strtol(temp_storage,NULL,10); // convert char array to int16_t
printf("temp var = %i \n",final_value);
}
}
return true;
}
}
The above method seems to work fine but I do not believe that this is the most appropriate solution for this particular task.
If you don't mind what the actual values of the enumeration constants are, you could define those values to be equivalent to the first two characters of the test string. You can then copy those first two characters into a variable of that enum type, which will then adopt the appropriate enumeration directly.
You can define the values using two-character integer literals (like 'BA'). On little-endian systems (such as Windows), the two characters would be in reverse order; for big-endian systems, they would be in direct order.
Here's an example little-endian implementation:
#include <stdio.h>
#include <string.h>
enum param_enum {
// Reverse byte order from strings for little-endian; keep "as-is" for big-endian...
AA = 'AA',
AB = 'BA',
AC = 'CA',
AD = 'DA'
};
int main(void)
{
char test[100];
while (1) {
printf("Enter test string (Q to quit): ");
if (scanf("%99s", test) != 1 || strcmp(test, "Q") == 0) break;
enum param_enum penum;
memset(&penum, 0, sizeof(penum)); // To clear any 'upper' bytes
memcpy(&penum, test, 2); // Now copy the first 2 byte2
switch (penum) {
case AA:
printf("Code is AA.\n");
break;
case AB:
printf("Code is AB.\n");
break;
case AC:
printf("Code is AC.\n");
break;
case AD:
printf("Code is AD.\n");
break;
default:
printf("Unknown code.\n");
break;
}
}
return 0;
}
If your compiler doesn't support multicharacter literals (such support is optional, according to the C Standard, IIRC), you can specify equivalent values using hexadecimal constants and the characters' ASCII codes (assuming your platforms uses ASCII encoding), instead:
enum param_enum {
AA = 0x4141, // 'AA'
AB = 0x4241, // 'BA'
AC = 0x4341, // 'CA'
AD = 0x4441 // 'DA'
};
You could use X Macro technique.
#define PARAM_XMACRO \
X(AA) \
X(AB) \
X(AC) \
X(AD)
enum param_enum{
#define X(NAME) NAME,
PARAM_XMACRO
#undef X
};
int process() {
...
char *val = (char*)param->write.value;
#define X(NAME) \
if (strcmp(val, #NAME ":") == 0) { \
printf(#NAME " parameter need to change\n"); \
return NAME; \
}
PARAM_XMACRO
#undef X
return -1;
}
It will expand as: (newlines added for clarity)
enum param_enum{
AA, AB, AC, AD,
};
int process() {
...
char *val = (char*)param->write.value;
if (strcmp(val, "AA" ":") == 0) {
printf("AA" " parameter need to change\n");
return AA;
}
if (strcmp(val, "AB" ":") == 0) {
printf("AB" " parameter need to change\n");
return AB;
}
if (strcmp(val, "AC" ":") == 0) {
printf("AC" " parameter need to change\n");
return AC;
}
if (strcmp(val, "AD" ":") == 0) {
printf("AD" " parameter need to change\n");
return AD;
}
return -1;
}
You could use a look-up table of strings indexed by the param enum, and a function to look up the param enum from the string:
enum param_enum {
AA,
AB,
AC,
AD
};
static const char * const param_prefix[] = {
[AA] = "AA",
[AB] = "AB",
[AC] = "AC",
[AD] = "AD",
};
#define ARRAYLEN(a) (sizeof (a) / sizeof (a)[0])
int find_param(const char *value, size_t value_len) {
int i;
const char *colon = memchr(value, ':', value_len);
if (!colon) {
/* not found */
return -1;
}
/* use length up to colon */
value_len = colon - value;
for (i = 0; i < ARRAYLEN(param_prefix); i++) {
if (param_prefix[i]) {
size_t prefix_len = strlen(param_prefix[i]);
if (value_len == prefix_len &&
memcmp(param_prefix[i], value, prefix_len) == 0) {
/* found */
return i;
}
}
}
/* not found */
return -1;
}
Example usage:
// (using 3 for length here, but should use something better)
int penum = find_param((char*)param->write.value, 3);
if(penum >= 0) {
printf("%s parameter need to change\n", param_prefix[penum]);
}

how to associate enum with array of string

If  I have array string for courses name like
courseName = {"java","math","physics"}
and enum have constant variables with code for courses like
CSC = 320
How to associate them in C language ?
You need some way to map the enumeration to the array index.
A simple array of structures with a "from" and "to" member solve it:
struct
{
int course; // Course enumeration value
unsigned name; // Name array index
} course_to_name_map[] = {
{ JAVA_101, 0 },
// etc...
};
To find the name loop over the mapping array to find the course, and then use the corresponding index to get the name:
char *get_course_name(int course)
{
static const size_t map_element_count = sizeof course_to_name_map / sizeof course_to_name_map[0];
for (unsigned i = 0; i < map_element_count; ++i)
{
if (course_to_name_map[i].course == course)
{
return course_names[course_to_name_map[i].name];
}
}
// Course was not found
return NULL;
}
Note that this is only one possible solution. It's simple but not very effective.
why not:
enum KEY {
KEY_JAVA = 320,
KEY_MATH = 123,
KEY_PHYSICS = 17,
};
char *course_to_name[] = {
[KEY_JAVA] = "java",
[KEY_MATH] = "math",
{KEY_PHYSIC] = "physics",
};
// usage:
course_to_name[KEY_JAVA];
It works quite well as long as courses codes are relatively small.

C programming: How to get rid of the QAC warning when pass 2D array as a const function argument?

I want to pass a 2D array to a function, and the value of the array will not be modified in that function. So I am thinking about doing this way:
#include <Windows.h>
static INT8 TwoDimArrayConst(const INT8 ai_Array[2][2]);
int main(void)
{
INT8 ai_Array[2][2] = { { { 1 }, { 2 } }, { { 3 }, { 4 } } };
(void)TwoDimArrayConst(ai_Array); // Message 0432: [C] Function argument is not of compatible pointer type.
return 1;
}
static INT8 TwoDimArrayConst(const INT8 ai_Array[2][2])
{
INT8 test = 0;
for (INT8 i = 0; i < 2; i++)
{
for (INT8 k = 0; k < 2; k++)
{
if (ai_Array[i][k] > 0)
{
test = 1;
}
}
}
if (test == 0)
{
test = 2;
}
return test;
}
However, it gave me the QAC error when I enabled depth 5 QAC setting as the one I put is the code comment above:
// Message 0432: [C] Function argument is not of compatible pointer type.
If I remove the const in the function declaration and definition, so the function is like:
static INT8 TwoDimArrayConst(INT8 ai_Array[2][2]);
this error will be gone, but there will be another error saying:
> The object addressed by the pointer parameter 'ai_Array' is not
> modified and so the pointer could be of type 'pointer to const'.
So how to resolve this dilemma? I cannot define ai_Array to be const array in the main fuction since some other function may still want to modify the value.
Also, I am looking for the solution that still maintain the double brackets(no need to pass row size and column size as separate arguments) in the function, instead of treat it as a 1D array.
the following proposed code:
uses the C library functions rather than the windows functions, since I'm running on linux, not windows
performs the desired functionality
cleanly compiles
takes advantage of arrays, in C, being laid out consecutively in memory
takes advantage of "accessing an array name degrades to the address of the first byte of the array"
removes all the unneeded braces (which are doing nothing but cluttering the code)
documents why each header file is included
passes the size of the array as an parameter to the called function (should always either do this or include some kind of 'marker' in the contents of the array)
all the above allows treating the array as a 1 dimensional array
breaks out of the loop in the called function as soon as the terminating condition is encountered
BTW: the header file: windows.h is not portable
and now, the proposed code:
//#include <Windows.h>
#include <stdio.h> // printf()
#include <stdint.h> // int8_t
static int8_t TwoDimArrayConst( const int8_t *ai_Array, size_t size );
int main(void)
{
const int8_t ai_Array[2][2] = { { 1, 2 }, { 3, 4 } };
int8_t returnValue = TwoDimArrayConst(( int8_t* const )ai_Array, sizeof( ai_Array) / sizeof( int8_t ));
printf( "%d\n", returnValue );
return 1;
}
static int8_t TwoDimArrayConst( const int8_t *ai_Array, size_t size )
{
int8_t test = 2;
for ( size_t i = 0; i < size; i++)
{
if (ai_Array[i] > 0)
{
test = 1;
break;
}
}
return test;
}
A run of the proposed code results in:
1

Dynamically enumerate keys in libconfig

in libconfig - is it possible to dymanically enumerate keys?
As an example, in this example config file from their repo - if someone invented more days in the hours section, could the code dynamically enumerate them and print them out?
Looking at the docs, I see lots of code to get a specific string, or list out an array, but I can't find an example where it enumerates the keys of a config section.
Edit
Received some downvotes, so thought I'd have another crack at being more specific.
I'd like to use libconfig to track some state in my application, read in the last known state when the app starts, and write it out again when it exits. My app stores things in a tree (of depth 2) - so this could be niceley represented as an associative array in a libconfig compatible file as below. The point is that the list of Ids (1234/4567) can change. I could track them in another array, but if I could just enumerate the 'keys' in the ids array below - that would be neater.
so
ids = {
"1234" = [1,2,3]
"4567" = [9,10,11,23]
}
e.g (psuedocode)
foreach $key(config_get_keys_under(&configroot)){
config_get_String($key)
}
I can't see anything obvious in the header file.
You can use config_setting_get_elem function to get n-th element of the group, array or list, and then (if it's group) use config_setting_name to get it's name. But AFAIK you can't use digits in key names. So consider following config structure:
ids = (
{
key = "1234";
value = [1, 2, 3];
},
{
key = "4567";
value = [9, 10, 11, 23];
}
);
Then you can easily enumerate through all members of the ids getting the values you want using the following code:
#include <stdio.h>
#include <libconfig.h>
int main(int argc, char **argv) {
struct config_t cfg;
char *file = "config.cfg";
config_init(&cfg);
/* Load the file */
printf("loading [%s]...\n", file);
if (!config_read_file(&cfg, file)) {
printf("failed\n");
return 1;
}
config_setting_t *setting, *member, *array;
setting = config_lookup(&cfg, "ids");
if (setting == NULL) {
printf("no ids\n");
return 2;
}
int n = 0, k, v;
char const *str;
while (1) {
member = config_setting_get_elem(setting, n);
if (member == NULL) {
break;
}
printf("element %d\n", n);
if (config_setting_lookup_string(member, "key", &str)) {
printf(" key = %s\n", str);
}
array = config_setting_get_member(member, "value");
k = 0;
if (array) {
printf(" values = [ ");
while (1) {
if (config_setting_get_elem(array, k) == NULL) {
break;
}
v = config_setting_get_int_elem(array, k);
printf("%s%d", k == 0 ? "" : ", ", v);
++k;
}
printf(" ]\n");
}
++n;
}
printf("done\n");
/* Free the configuration */
config_destroy(&cfg);
return 0;
}

Syntax for assigning to a struct in a struct

I have a struct Entity that is made up of Limbs and an enum, Limbs is also a struct with two items e.g.
typedef enum{ALIVE, DEAD} state;
typedef struct Limb{
int is_connected;
int is_wounded;
} Limb;
typedef struct Entity{
Limb limb_1;
Limb limb_2;
state is_alive;
} Entity;
Now lets say I have a function that's designed to assign entity particular values, what is the proper syntax to use here? My current guess is this:
void assign_entity(Entity *entity){
*entity = {
.limb_1 = { 1, 0 },
.limb_2 = { 1, 0 },
.is_alive = ALIVE
};
}
But I get an error (expected expression) when I use this syntax, what am I doing wrong here? What is the proper syntax for assigning to a struct inside a struct.
You're trying to use a compound literal but omitting the proper syntax.
It should be:
void assign_entity(Entity *entity){
*entity = ((Entity) {
.limb_1 = { 1, 0 },
.limb_2 = { 1, 0 },
.is_alive = ALIVE
});
}
Note that this requires C99 (or a suitably extended compiler, of course).
Probably too verbose for someone the code below:
void assign_entity(Entity *entity)
{
entity->limp_1.is_connected = 1;
entity->limp_1.is_wounded= 0;
entity->limp_2.is_connected = 1;
entity->limp_2.is_wounded= 0;
entity->is_alive = ALIVE;
}
If you have already allocated memory at the address pointed to by entity and all you're trying to do is "assign particular values", then you would do it as follows:
void assign_entity(Entity *entity)
{
entity->limb_1 = ( 1, 0 );
entity->limb_2 = ( 1, 0 );
entity->is_alive = ALIVE;
}
Or, if you want to roll it all up into one line:
void assign_entity(Entity *entity)
{
*entity = ((1, 0), (1, 0), ALIVE);
}
Designated initializer syntax can only be used in an initialization.
One way to do what you want would be:
Entity const new = {
.limb_1 = { 1, 0 },
.limb_2 = { 1, 0 },
.is_alive = ALIVE
};
*entity = new;

Resources