How to decalre array of enums? - c

I have the following enum:
enum {
ClientRx,
ClientTx,
Server1Rx,
Server1Tx,
Server1RxDropped,
Server1TxDropped,
Server2Rx,
Server2Tx,
Server2RxDropped,
Server2TxDropped,
Server3Rx,
Server3Tx,
Server3RxDropped,
Server3TxDropped,
Server4Rx,
Server4Tx,
Server4RxDropped,
Server4TxDropped,
MaxVal
};
Is there a way to create an array of server enums that will fit in original enum to make this code more generic? (e.g. If I want to extend number of server counters to 100...)
Something in the form:
typedef enum {
ServerRx,
ServerTx,
ServerRxDropped,
ServerTxDropped
}eServerCounters;
eServerCounters ServerCountersArray[4];
enum {
ClientRx,
ClientTx,
ServerCountersArray,
MaxVal
};
Get enum value:
ServerCountersArray[2].ServerRx

In C enumerations are a way to create symbolic integer constants in the global namespace.
With your definition
eServerCounters ServerCountersArray[4];
you create an array of four elements. Each element can have any of the values from the eServerCounters enumeration.
For example you can check if the third element is equal to ServerRx like
if (ServerCountersArray[2] == ServerRx) ...
Of perhaps you need to swtich between the different values:
switch (ServerCountersArray[i])
{
case ServerRx:
// Do something here...
break;
case ServerTx:
// Do something here...
break;
case ServerRxDropped:
// Do something here...
break;
case ServerTxDropped:
// Do something here...
break;
}
Thinking a little more about the code and the comments by Cheatah, it seems like what you might need is an array of structures:
struct counter
{
unsigned rx;
unsigned tx;
unsigned rx_dropped;
unsigned tx_dropped;
};
struct counter counters[4];
Now you can access the counter for a specific "channel" from the array, like e.g.
for (unsigned ch = 0; ch < 4; ++ch)
{
printf("Channel %u:\n", ch + 1);
printf(" Rx: %u (dropped %u)\n", counters[ch].rx, counters[ch].rx_dropped);
printf(" Tx: %u (dropped %u)\n", counters[ch].tx, counters[ch].tx_dropped);
}

You need to generate large enun definition
int main(int argc, char **argv)
{
int nservers = -1;
printf("typedef enum {\n"
"\t\tClientRx,\n"
"\t\tClientTx,\n\n");
if(argc > 1 && sscanf(argv[1], "%d", &nservers) == 1 && nservers != -1)
{
for(int server = 1; server <= nservers; server++)
{
printf("\t\tServer%dRx,\n" , server);
printf("\t\tServer%dTx,\n" , server);
printf("\t\tServer%dRDropped,\n" , server);
printf("\t\tServer%dTxDropped,\n\n" , server);
}
}
printf("} serverEnumType;\n");
}
https://godbolt.org/z/sTGezaer7

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

Call c functions from fortran(type enum)

Recently,I call c function from fortran with iso_c_binding.But I found some c code.such as:
typedef enum
{
STRUMPACK_FLOAT,
STRUMPACK_DOUBLE,
STRUMPACK_FLOATCOMPLEX
} STRUMPACK_PRECISION;
typedef enum
{
STRUMPACK_MT,
STRUMPACK_MPI_DIST
} STRUMPACK_INTERFACE;
typedef struct
{
int solver;
STRUMPACK_PRECISION precision1;
STRUMPACK_INTERFACE interface1;
}STRUMPACK_SparseSolver;
int STRUMPACK_init(STRUMPACK_SparseSolver * S,
STRUMPACK_PRECISION precision1, STRUMPACK_INTERFACE interface1, int verbose)
{
S->precision1 = precision1;
S->interface1 = interface1;
switch (interface1)
{
case STRUMPACK_MT:
{
switch (precision1)
{
case STRUMPACK_FLOAT:
printf("srtumpack_float %d\n", verbose);
break;
case STRUMPACK_DOUBLE:
printf("srtumpack_double %d\n", verbose);
break;
default:
printf("ERROR: wrong precision!");
}
}
break;
default:
printf("ERROR: wrong interface!");
}
return 0;
}
I don't know that call this c subfunction with Fortran.because of this structs:
typedef enum
{
STRUMPACK_MT,
STRUMPACK_MPI_DIST
} STRUMPACK_INTERFACE;
I don't know how to solve this problem . I will appreciate any contribution, suggestion about the problem.
Thanks
That isn't a structure, but an enum (enumeration) supported by ISO binding entity ENUM.
In case your binding miss enumerations the following is a workaround.
Enums in C are more or less constant integers which values are assigned by compiler in generally increasing way. You can also force values for each enum member using assignment as in:
typedef enum
{
STRUMPACK_FLOAT = 0,
STRUMPACK_DOUBLE,
STRUMPACK_FLOATCOMPLEX = 100
} STRUMPACK_PRECISION
In this case i.e. we impose to STRUMPACK_FLOATCOMPLEX the value 100. We made the same with the first member, in any case the first member have value 0 by default. The second member STRUMPACK_DOUBLE will get the value 1 as progressive increment from previous member.
Anyway you can get better info on how enum works googling on the net.
In your case the easier way to solve the problem is to convert enums in definitions and using int's as type like in:
#define STRUMPACK_FLOAT 0
#define STRUMPACK_DOUBLE 1
#define STRUMPACK_FLOATCOMPLEX 2
typedef int STRUMPACK_PRECISION;
#define STRUMPACK_MT 0
#define STRUMPACK_MPI_DIST 1
typedef int STRUMPACK_INTERFACE;
typedef struct
{
int solver;
STRUMPACK_PRECISION precision1;
STRUMPACK_INTERFACE interface1;
} STRUMPACK_SparseSolver;
int STRUMPACK_init(STRUMPACK_SparseSolver * S, STRUMPACK_PRECISION precision1,
STRUMPACK_INTERFACE interface1, int verbose)
{
S->precision1 = precision1;
S->interface1 = interface1;
switch (interface1)
{
case STRUMPACK_MT:
{
switch (precision1)
{
case STRUMPACK_FLOAT:
printf("srtumpack_float %d\n", verbose);
break;
case STRUMPACK_DOUBLE:
printf("srtumpack_double %d\n", verbose);
break;
default:
printf("ERROR: wrong precision!");
}
}
break;
default:
printf("ERROR: wrong interface!");
}
return 0;
}

can we use switch-case statement with strings in c? [duplicate]

This question already has answers here:
How can I compare strings in C using a `switch` statement?
(16 answers)
Closed 5 years ago.
int a = 0 , b = 0;
char* c = NULL;
int main(int argc , char ** argv){
c = argv[2];
a = atoi(argv[1]);
b = atoi(argv[3]);
switch(c){
case "+": printf(a+b);
break;
}
printf("\n\n");
return 0;
}
No, you can't. Switch is intended to compare numeric types, and for extension char types.
Instead you should use the strcmp function, included in string header:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
if (argc != 4) {
puts("Incorrect usage");
return 1;
}
/* You should check the number of arguments */
char * op = argv[1];
int a = atoi(argv[2]);
int b = atoi(argv[3]);
/* You should check correct input too */
if (strcmp(op, "+") == 0)
printf("%d + %d = %d\n", a, b, a + b);
else if (strcmp(op, "-") == 0)
printf("%d - %d = %d\n", a, b, a - b);
/* Add more functions here */
return 0;
}
No you can't. The case labels of a switch need to be compile time evaluable constant expressions with an integral type.
But int literals like '+' satisfy that requirement. (As do enum values for that matter.)
Some folk like to use implementation-defined multi-character literals (e.g. 'eax') as case labels as they claim it helps readability, but at that point, you're giving up consistent behaviour across different platforms.
If you need to branch on the value of a NUL-terminated char array, then use an if block.
There are two cases to the answer ..
Firstly 6.8.4.2 (switch case)
The controlling expression of a switch statement shall have integer
type
Secondly 6.8.4.2 (the case statements)
The expression of each case label shall be an integer constant
expression and no two of the case constant expressions in the same
switch statement shall have the same value after conversion
Long story short - you can't use string literal like that. Neither in switch controlling expression nor in case.
You can do the string comparisons using strcmp and then do the if-else conditioning. The context on which you ask this, you can simply pass the character + (argv[2][0]) instead of passing the whole literal. That way you will be passing char to the switch expression and then work accordingly.
Nope, that's not possible.
Quoting C11, chapter §6.8.4.2
The controlling expression of a switch statement shall have integer type.
in your case, you don't seem to need a string but rather the first (and only character) of the string passed in the switch statement, in that case that's possible using character literal (which has integer type) in the case statements:
if (strlen(c)==1)
{
switch(c[0]){
case '+': printf(a+b);
break;
...
}
}
some good other alternatives are described in best way to switch on a string in C when the string has multiple characters.
Not directly. But yes, you can.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
// The way you store and search for names is entirely
// up to you. This is a simple linear search of an
// array. If you have a lot of names, you might choose
// a better storage + lookup, such as a hash table.
int find( const char** ss, int n, const char* s )
{
int i = 0;
while (i < n)
if (strcmp( ss[i], s ) == 0) break;
else i += 1;
return i;
}
// A bevvy of little utilities to help out.
char* strupper( char* s )
{
char* p = s;
while ((*p = toupper( *p ))) ++p;
return s;
}
char* zero( char* p ) { if (p) *p = 0; return p; }
#define STRINGIFY(S) STRINGIFY0(S)
#define STRINGIFY0(S) #S
int main()
{
// Our list of names are enumerated constants with associated
// string data. We use the Enum Macro Trick for succinct ODR happiness.
#define NAMES(F) \
F(MARINETTE) \
F(ADRIAN) \
F(ALYA) \
F(DINO)
#define ENUM_F(NAME) NAME,
#define STRING_F(NAME) STRINGIFY(NAME),
enum names { NAMES(ENUM_F) NUM_NAMES };
const char* names[ NUM_NAMES ] = { NAMES(STRING_F) NULL };
#undef STRING_F
#undef ENUM_F
#undef NAMES
// Ask user for a name
char s[ 500 ];
printf( "name? " );
fflush( stdout );
fgets( s, sizeof( s ), stdin );
zero( strchr( s, '\n' ) );
// Preprocess and search for the name
switch (find( names, sizeof(names)/sizeof(*names), strupper( s ) ))
{
case MARINETTE: puts( "Ladybug!" ); break;
case ADRIAN: puts( "Chat Noir!" ); break;
case ALYA:
case DINO: puts( "Best friend!" ); break;
default: puts( "Who?" );
}
}
Keep in mind this works by pure, unadulterated magic tricks, and is not suitable for large collections of text values.
Also, the validity of the match is entirely dependent on the degree to which you pre-process the user’s input. In this example we only ignore case, but a more advanced application might perform some more sophisticated matching.
As others pointed out in C one cannot use a string as argument to a switch, nor to its case-labels.
To get around this limitation one could map each string to a specific integer and pass this to the switch.
Looking up the mapping requires searching the map, which can be done using the Standard C bsearch() function.
An example might look like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <search.h>
enum Operation {
OP_INVALID = -1,
OP_ADD,
OP_SUBTRACT,
OP_MULTIPLY,
OP_DIVIDE,
OP_MAX
};
struct Operation_Descriptor {
char * name;
enum Operation op;
};
struct Operation_Descriptor operations [] = {
{"add", OP_ADD},
{"subtract", OP_SUBTRACT},
{"multiply", OP_MULTIPLY},
{"divide", OP_DIVIDE}
};
int cmp(const void * pv1, const void * pv2)
{
const struct Operation_Descriptor * pop1 = pv1;
const struct Operation_Descriptor * pop2 = pv2;
return strcmp(pop1->name, pop2->name);
}
int main(int argc, char ** argv)
{
size_t s = sizeof operations / sizeof *operations;
/* bsearch() requires the array to search to be sorted. */
qsort(operations, s, sizeof *operations, cmp);
{
struct Operation_Descriptor * pop =
bsearch(
&(struct Operation_Descriptor){argv[1], OP_INVALID},
operations, s, sizeof *operations, cmp);
switch(pop ?pop->op :OP_INVALID)
{
case OP_ADD:
/* Code to add goes here, */
break;
case OP_SUBTRACT:
/* Code to subtract goes here, */
break;
case OP_MULTIPLY:
/* Code to multiply goes here, */
break;
case OP_DIVIDE:
/* Code to divide goes here, */
break;
case OP_INVALID:
default:
fprintf(stderr, "unhandled or invalid operation '%s'\n", argv[1]);
break;
}
}
}
If on POSIX one can even use a hash table, which is the fastest way to lookup the mapping.
An example might look like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <search.h>
enum Operation {
OP_INVALID = -1,
OP_ADD,
OP_SUBTRACT,
OP_MULTIPLY,
OP_DIVIDE,
OP_MAX
};
struct Operation_Descriptor {
char * name;
enum Operation op;
};
struct Operation_Descriptor operations [] = {
{"add", OP_ADD},
{"subtract", OP_SUBTRACT},
{"multiply", OP_MULTIPLY},
{"divide", OP_DIVIDE}
};
int main(int argc, char ** argv)
{
if (0 == hcreate(5))
{
perror("hcreate() failed");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < s; ++i)
{
if (!hsearch((ENTRY){operations[i].name, &operations[i].op}, ENTER))
{
perror("hsearch(ENTER) failed");
exit(EXIT_FAILURE);
}
}
{
ENTRY * ep = hsearch((ENTRY){argv[1], NULL}, FIND);
switch(ep ?*((enum Operation *)ep->data) :OP_INVALID)
{
case OP_ADD:
/* Code to add goes here, */
break;
case OP_SUBTRACT:
/* Code to subtract goes here, */
break;
case OP_MULTIPLY:
/* Code to multiply goes here, */
break;
case OP_DIVIDE:
/* Code to divide goes here, */
break;
case OP_INVALID:
default:
fprintf(stderr, "unhandled or invalid operation '%s'\n", argv[1]);
break;
}
}
hdestroy(); /* Clean up. */
}

How to use global variables on a state machine

I made this state machine :
enum states { STATE_ENTRY, STATE_....} current_state;
enum events { EVENT_OK, EVENT_FAIL,EVENT_REPEAT, MAX_EVENTS } event;
void (*const state_table [MAX_STATES][MAX_EVENTS]) (void) = {
{ action_entry , action_entry_fail , action_entry_repeat }, /*
procedures for state 1 */
......}
void main (void){
event = get_new_event (); /* get the next event to process */
if (((event >= 0) && (event < MAX_EVENTS))
&& ((current_state >= 0) && (current_state < MAX_STATES))) {
state_table [current_state][event] (); /* call the action procedure */
printf("OK 0");
} else {
/* invalid event/state - handle appropriately */
}
}
When I modify a global variable in one state the global variable remain the same , and I need that variable in all the states . Do you now what could be the problem ?
My Global variable is this structure:
#if (CPU_TYPE == CPU_TYPE_32)
typedef uint32_t word;
#define word_length 32
typedef struct BigNumber {
word words[64];
} BigNumber;
#elif (CPU_TYPE == CPU_TYPE_16)
typedef uint16_t word;
#define word_length 16
typedef struct BigNumber {
word words[128];
} BigNumber;
#else
#error Unsupported CPU_TYPE
#endif
BigNumber number1 , number2;
Here is how I modify:
//iterator is a number from where I start to modify,
//I already modified on the same way up to the iterator
for(i=iterator+1;i<32;i++){
nr_rand1=661;
nr_rand2=1601;
nr_rand3=1873;
number2.words[i]=(nr_rand1<<21) | (nr_rand2<<11) | (nr_rand3);
}
This is just in case you may want to change your approach for defining the FSM. I'll show you with an example; say you have the following FSM:
You may represent it as:
void function process() {
fsm {
fsmSTATE(S) {
/* do your entry actions heare */
event = getevent();
/* do you actions here */
if (event.char == 'a') fsmGOTO(A);
else fsmGOTO(E);
}
fsmSTATE(A) {
event = getevent();
if (event.char == 'b' || event.char == 'B') fsmGOTO(B);
else fsmGOTO(E);
}
fsmSTATE(B) {
event = getevent();
if (event.char == 'a' ) fsmGOTO(A);
else fsmGOTO(E);
}
fsmSTATE(E) {
/* done with the FSM. Bye bye! */
}
}
}
I do claim (but I believe someone will disagree) that this is simpler, much more readable and directly conveys the structure of the FSM than using a table. Even if I didn't put the image, drawing the FSM diagram would be rather easy.
To get this you just have to define the fsmXXX stuff as follows:
#define fsm
#define fsmGOTO(x) goto fsm_state_##x
#define fsmSTATE(x) fsm_state_##x :
Regarding the code that changese number2:
for(i=iterator+1;i<32;i){
nr_rand1=661;
nr_rand2=1601;
nr_rand3=1873;
number2.words[i]=(nr_rand1<<21) | (nr_rand2<<11) | (nr_rand3);
}
I can't fail to note that:
i is never incremented, so just one element of the array is changed (iterator+1) over an infinite loop;
even if i would be incremented, only the a portion of the words array it's changed depending on the value of iterator (but this might be the intended behaviour).
unless iterator can be -1, the element words[0] is never changed (again this could be the intended behaviour).
I would check if this is really what you intended to do.
If you're sure that it's just a visibility problem (since you said that when you declare it as local it worked as expected), the only other thing that I can think of is that you have the functions in one file and the main (or where you do your checks) in another.
Then you include the same .h header in both files and you end up (due to the linker you're using) with two different number2 because you did not declare it as extern in one of the two files.
Your compiler (or, better, the linker) should have (at least) warned you about this, did you check the compilation messages?
This is not an answer - rather it is a comment. But it is too big to fit the comment field so I post it here for now.
The code posted in the question is not sufficient to find the root cause. You need to post a minimal but complete example that shows the problem.
Something like:
#include<stdio.h>
#include<stdlib.h>
#include <stdint.h>
typedef uint32_t word;
#define word_length 32
typedef struct BigNumber {
word words[4];
} BigNumber;
BigNumber number2;
enum states { STATE_0, STATE_1} current_state;
enum events { EVENT_A, EVENT_B } event;
void f1(void)
{
int i;
current_state = STATE_1;
for (i=0; i<4; ++i) number2.words[i] = i;
}
void f2(void)
{
int i;
current_state = STATE_0;
for (i=0; i<4; ++i) number2.words[i] = 42 + i*i;
}
void (*const state_table [2][2]) (void) =
{
{ f1 , f1 },
{ f2 , f2 }
};
int main (void){
current_state = STATE_0;
event = EVENT_A;
state_table [current_state][event] (); /* call the action procedure */
printf("%u %u %u %u\n", number2.words[0], number2.words[1], number2.words[2], number2.words[3]);
event = EVENT_B;
state_table [current_state][event] (); /* call the action procedure */
printf("%u %u %u %u\n", number2.words[0], number2.words[1], number2.words[2], number2.words[3]);
return 0;
}
The above can be considered minimal and complete. Now update this code with a few of your own functions and post that as the question (if it still fails).
My code doesn't fail.
Output:
0 1 2 3
42 43 46 51

Best choice for very simple lookup table

I am reading a file with commands that are [a-zA-Z][a-zA-Z0-9], i.e., two chars. There is a total of 43 different commands, and I would like to transform the two chars to a number (1..43).
How would you proceed? I was thinking on creating an array of 43 unsigned shorts (two bytes) each corresponding to the two chars of each command, and then doing something like:
//char1: first char of cmd, char2: second char of cmd, lut: array of 43 shorts.
unsigned short tag;
tag = (char1 << 8) | char2;
for(int i=1;i<=43;i++) {
if(tag==lut[i-1]) return i;
}
return 0;
The thing is I'm not sure if this is the best way for doing what I want. I guess that with just 43 elements it won't matter, but that list might increase in the future.
Here is a method I used on an old project. One big drawback to this method is the lookup table and enum are dependent on each other and need to be kept synchronized. I got this method from an online article quite a few years ago, but don't remember where. This is a complete example:
#include <stdio.h>
#include <string.h>
#define CMDSIZE 2
const char* cmd_table[] = { "qu",
"qr",
"fi",
"he"};
enum { CMD_QUIT,
CMD_QUIT_RESTART,
CMD_FILE,
CMD_HELP,
CMD_NONE };
int lookup(char command[])
{
int i = 0;
int cmdlength = strlen(command);
for (i = 0; i < cmdlength; i++)
{
command[i] = tolower(command[i]);
}
const int valid_cmd = sizeof cmd_table / sizeof *cmd_table;
for (i = 0; i < valid_cmd; i++)
{
if (strcmp(command, cmd_table[i]) == 0)
return i;
}
return CMD_NONE;
}
int main()
{
char key_in[BUFSIZ];
char command[CMDSIZE+1];
// Wait for command
do
{
printf("Enter command: ");
fgets(key_in, BUFSIZ, stdin);
key_in[strlen(key_in)-1] = '\0';
strncpy(command, key_in, CMDSIZE);
command[CMDSIZE] = '\0';
switch (lookup(command))
{
case CMD_QUIT:
printf ("quit\n");
break;
case CMD_QUIT_RESTART:
printf ("quit & restart\n");
break;
case CMD_FILE:
printf ("file\n");
break;
case CMD_HELP:
printf("help\n");
break;
case CMD_NONE:
if(strcmp(key_in, ""))
printf("\"%s\" is not a valid command\n", key_in);
break;
}
} while (strcmp(command, "qu"));
return 0;
}
EDIT:
I found the article I mentioned:
https://www.daniweb.com/software-development/cpp/threads/65343/lookup-tables-how-to-perform-a-switch-using-a-string

Resources