2016-07-27 21 views
5

Ist es möglich, das Folgende neu zu schreiben, so dass ich nur an einer Stelle wechseln muss, wenn sich die Zeichenkette ändert?Wie kann ich automatisch das erste Zeichen einer konstanten Zeichenkette als konstantes Zeichen erhalten?

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

Das folgende ist nicht akzeptabel, da sie in einer Speicherstelle zu einem char Bezug nehmen, so kann es nicht als ein Fall in einer switch Anweisung verwendet werden:

#define MY_STRING_FIRST_CHAR MY_STRING[0] 

switch (something) { 
    case MY_STRING_FIRST_CHAR: 
     break; 
} 

Der Zweck ist, effizient Analysieren einer empfangenen Zeichenfolge durch Betrachten eines Zeichens. In meinem Fall haben alle Strings ein eindeutiges Zeichen. Das Folgende ist nicht mein eigentlicher Code, sondern ein sehr einfaches Beispiel, das Prinzip zu zeigen:

#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“ fand diese in der gcc Dokumentation: „Es gibt keine Möglichkeit, ein Makro-Argument in ein Zeichen zu konvertieren Konstante."

Ich wollte, dass die Definitionen in einer Include-Datei enthalten sind, die von mehreren Quelldateien gemeinsam genutzt werden kann. Das ist so nah, wie ich während nur jedes Zeichen haben an einem Ort definiert bekommen kann:

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

Ich werde es auf diese Weise nicht tun. Die ursprüngliche Frage war, ob es möglich ist, eine Definition zu teilen, um sowohl eine Zeichenkette als auch eine Zeichenkonstante zu erhalten. Durch die Verschwendung von Taktzyklen zur Laufzeit gibt es mehrere Lösungen für mein Problem.

+3

Interessante Frage zu bewegen. Ich bezweifle, dass es möglich ist. Aber riecht nach XY-Problem für mich. –

+1

Wenn Sie das Zeichen in einer Groß-/Kleinschreibung verwenden möchten, benötigen Sie einen [ganzzahligen Konstantenausdruck] (http://port70.net/~nsz/c/c99/n1256.html#6.6). – nwellnhof

+0

Mögliches Duplikat von [Schalter Groß-/Kleinschreibung: Fehler: Groß-/Kleinschreibung wird nicht auf eine Ganzzahlkonstante reduziert] (http://stackoverflow.com/questions/14069737/switch-case-error-case-label-does-not-reduceto- -an-integer-constant) – jweyrich

Antwort

-4
#define MY_STRING "Hello" 

const char var[] = MY_STRING; 

switch(var[0]) { 
    case 'H': 
    break; 
    case 'A': 
    break; 
} 

Dies sollte es lösen.

+3

Kann es in einer 'switch' Anweisung verwendet werden? Leute, lies die Frage, bevor du antwortest! –

+1

Bitte lesen Sie die (aktualisierte) Frage sorgfältig – Leon

3

Sie können jedes Symbol tun, dass einmal mit dem Schreiben ... aber auf unterschiedliche Definitionen

#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; 
} 
+0

Oooops, ich sah das, nachdem ich mein ähnliches, aber hässlicheres Beispiel dem ursprünglichen Beitrag hinzugefügt hatte. Ihre Lösung ist eleganter. – Hans

+2

Meine hässliche Lösung hat die String-Länge nicht explizit angegeben, aber es scheint, dass die Konstante '5' auch aus Ihrem Code entfernt werden kann. – Hans

1

Warum wollen Sie unbedingt ein Schaltergehäuse benutzen?

Stattdessen könnten Sie eine Mapping-Tabelle verwenden, die Ihrer Zeichenkette und der Handling-Funktion entspricht. Dann müssen Sie einfach über die Tabelle iterieren.

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

Dann müssen Sie nur noch den Verarbeitungscode von Ihrem Switch/Fall in die entsprechende Behandlungsfunktion

+1

Dieser Code fehlt die gesuchte Effizienz im Vergleich zu dem "Switch" -basierten Ansatz, der in O (1) -Zeit funktionieren würde. Ob die Leistung dieses Codes wirklich so wichtig ist, kann nur OP sagen. – Leon

+0

@Leon Ich stimme deiner Aussage nicht zu. Aus Performance-Sicht müssen Sie Compiler-Optimierungen berücksichtigen. Mit dem obigen Code würde jeder moderne Compiler, der für Leistungsoptimierungen konfiguriert ist, ein Loop-Abrolling durchführen, das den resultierenden Binärcode fast zu dem eines einfachen Schalters/Falls macht. Es ist sehr oft eine schlechte Idee, die Codelesbarkeit zu opfern, um frühe Optimierungen zu machen, die der Compiler besser machen könnte als Sie. – greydet

+0

Loop-Abrollung kann nicht die Leistung einer konstanten Zeitabfrage über eine Tabelle erreichen. Was ist mit Lesbarkeit und Leistung, stimme ich Ihnen zu, und mein erster Kommentar enthält einen Hinweis darauf. – Leon