Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I automatically get the first character of a constant string as a constant character?

Tags:

c

gcc

constants

Is it possible to rewrite following so I only have to change in one place if the string changes?

#define MY_STRING "Foo bar"
#define MY_STRING_FIRST_CHAR 'F'

The following is not acceptable since it refers to a char in a memory location, so it can't be used as a case in a switch statement:

#define MY_STRING_FIRST_CHAR MY_STRING[0]

switch (something) {
    case MY_STRING_FIRST_CHAR:
        break;
}

The purpose is to efficiently parse a received string by looking at one character. In my case all strings have one unique character. The following is not my actual code, but a very simple example to show the principle:

#define COMMAND_LIST              "list"
#define COMMAND_LIST_FIRST_CHAR   'l'
#define COMMAND_CHANGE            "change"
#define COMMAND_CHANGE_FIRST_CHAR 'c'
#define COMMAND_EXIT              "exit"
#define COMMAND_EXIT_FIRST_CHAR   'e'

switch(received_command_string[0]){
  case COMMAND_LIST_FIRST_CHAR:
    // Do the "list" stuff
    break;
  case COMMAND_CHANGE_FIRST_CHAR:
    // Do the "change" stuff
    break;
  case COMMAND_EXIT_FIRST_CHAR:
    // Do the "exit" stuff
    break;
}

User "pmg" found this in the gcc documentation: "There is no way to convert a macro argument into a character constant."

I wanted the definitions to be in an include file that can be shared by several source files. This is as close as I can get while only have every character defined in one place:

#include <stdio.h>
#define CH0 'F'
#define CH1 'o'
#define CH2 'o'
#define CH3 ' '
#define CH4 'b'
#define CH5 'a'
#define CH6 'r'
static char MY_STRING[] = { CH0, CH1, CH2, CH3, CH4, CH5, CH6, '\0'};
#define MY_STRING_FIRST_CHAR CH0

void main(void){
  printf("The string is %s, the first char is %c\n", MY_STRING, MY_STRING_FIRST_CHAR);
}

I will not do it that way. The original question was if it is possible to share one definition to get both a string constant and a character constant. By wasting clock cycles at run-time there are several solutions to my problem.

like image 380
Hans Avatar asked Nov 20 '22 23:11

Hans


2 Answers

You can do that with writing each symbol once ... but on different definitions

#include <stdio.h>

#define COMMAND_LIST_FIRST_CHAR   'l'
#define COMMAND_LIST              (char[]){ COMMAND_LIST_FIRST_CHAR, 'i', 's', 't', 0 }

int main(void) {
    char received_command_string[] = "list";
    switch (received_command_string[0]) {
        case COMMAND_LIST_FIRST_CHAR:
            printf("Doing the \"list\" stuff for '%s'\n", COMMAND_LIST);
            break;
        default:
            break;
    }
    return 0;
}
like image 120
pmg Avatar answered Nov 22 '22 14:11

pmg


Why do you absolutely want to use a switch case?

Instead you could use a mapping table that match your string and the handling function. Then you simply have to iterate over the table.

typedef struct {
    char * key;
    void (func*)(void);
} MAP_ENTRY;

MAP_ENTRY map [] = {
    {"list", listHandler},
    {"change", changeHandler},
    {"exit", exitHandler},
};

for (i = 0; i < sizeof(map)/sizeof(map[0]); i++) {
    if (map[i].key[0] == received_command_string[0]) {
        map[i].func();
        break;
    }
}

Then you just have to move the processing code from your switch/case into the corresponding handler function

like image 27
greydet Avatar answered Nov 22 '22 15:11

greydet