Der beste Weg, um einen String in C einzuschalten

83

In C gibt es ein switchKonstrukt, das es einem ermöglicht, verschiedene bedingte Codezweige basierend auf einem ganzzahligen Testwert auszuführen, z.

int a;
/* Read the value of "a" from some source, e.g. user input */
switch ( a ) {
case 100:
  // Code
  break;
case 200:
  // Code
  break;
default:
  // Code
  break;
}

Wie ist es möglich, dasselbe Verhalten (dh vermeiden Sie die sogenannte " if- elseLeiter") für einen Zeichenfolgenwert, dh a, zu erhalten char *?

Niklas
quelle
Was meinst du mit "einschalten"?
Kennytm
Bitte formulieren Sie neu, damit die Frage klar macht, was Sie tatsächlich versuchen (oder fragen).
Šimon Tóth
8
Das OP möchte wahrscheinlich eine Zeichenfolge als Parameter für eine switch-Anweisung verwenden. Soweit ich weiß, ist dies nicht möglich.
Dandan78

Antworten:

99

Wenn Sie meinen, wie man etwas Ähnliches schreibt:

// switch statement
switch (string) {
  case "B1": 
    // do something
    break;
  /* more case "xxx" parts */
}

Dann besteht die kanonische Lösung in C darin, eine If-else-Leiter zu verwenden:

if (strcmp(string, "B1") == 0) 
{
  // do something
} 
else if (strcmp(string, "xxx") == 0)
{
  // do something else
}
/* more else if clauses */
else /* default: */
{
}
Bart van Ingen Schenau
quelle
1
Eigentlich ist das Problem, dass ich bereits einen Schalter auf int habe und in einem speziellen Fall die Werte "B1" und "B2" habe, die ich in demselben Schalter verwenden möchte. Die einzige Möglichkeit besteht darin, die Werte "B1" und "B2" irgendwie zu konvertieren und als int zu verwenden !!?
Niklas
2
@Niklas: Dies sind wichtige Informationen für Ihre Frage. Können Sie Ihre Frage aktualisieren und (wenn möglich mit einem (Pseudo-) Code) erklären, was Sie versuchen zu tun?
Bart van Ingen Schenau
4
@Niklas: Du solltest deine Frage klären: Wie um alles in der Welt könnten "B1" und "B2" ein Sonderfall eines Int sein?
Edgar Bonet
1
#define A 1 #define B 2 #define C S1 #define D S2 und diese Werte möchte ich in meinem Switch verwenden. So einfach :-)
Niklas
5
@Niklas: Definitionen sind keine Strings. Wenn die Definition für eine Zahl ist, können Sie sie wie folgt direkt in Ihrem Switch verwenden switch (something) { case A: /*...*/ break; case B: /*...*/ break; }.
Bart van Ingen Schenau
43

Wenn Sie viele Fälle haben und nicht viele strcmp()Anrufe schreiben möchten , können Sie Folgendes tun:

switch(my_hash_function(the_string)) {
    case HASH_B1: ...
    /* ...etc... */
}

Sie müssen nur sicherstellen, dass Ihre Hash-Funktion keine Kollisionen innerhalb der Menge möglicher Werte für die Zeichenfolge aufweist.

Edgar Bonet
quelle
7
"Stellen Sie sicher, dass Ihre Hash-Funktion keine Kollisionen innerhalb des Satzes möglicher Werte für die Zeichenfolge aufweist." - Gibt es eine solche Hash-Funktion für das Alphabet [a-zA-Z0-9_]? Irgendein Beispiel?
Arun
8
@ArunSaha: Offensichtlich nicht für beliebige Kombinationen solcher Zeichen.
Edgar Bonet
2
Wenn Sie Zeichenfolgenschlüssel mit fester Länge verwenden, können Sie diese jeweils in eindeutige Ganzzahlen konvertieren. keine kollisionen möglich.
Ingenieur
@ArcaneEngineer Ähm ... ist das nicht das genaue Problem, das die Frage zu lösen versucht? Wie würden Sie, wenn Sie nur die Zeichenfolge angeben, eine dazu passende Ganzzahl auswählen? "benutze einen Schalter oder wenn / sonst Leiter" Oder meinst du etwas sehr Kurzes wie 4 Zeichen?
Ebyrob
@ebyrob Ich meinte alles Vergleichbare in einer schnellen Operation, wie 2 64-Bit- uints, deren Bits als 8 1-Byte- ASCIIs behandelt werden char. Ich habe dies vor einiger Zeit für Schlüsselvergleiche innerhalb einer Hash-Tabelle in C implementiert. Sie eliminieren somit die Notwendigkeit von Hashing oder Buckets. Das Problem tritt dort auf, wo Sie 64 Bit überschreiten müssen. Sie zahlen dann die Kosten für Bedingungen, während Sie jeden Satz von 8 chars in der vollständigen Zeichenfolge durchlaufen. Es sei denn, Sie rollen die Schleife ab, wenn Sie die maximale Größe der Schlüssel kennen. Es ist ein feiner Balanceakt.
Ingenieur
37

In C gibt es keine Möglichkeit, dies zu tun. Es gibt viele verschiedene Ansätze. In der Regel ist es am einfachsten, eine Reihe von Konstanten zu definieren, die Ihre Zeichenfolgen darstellen, und nach Zeichenfolgen zu suchen, um die Konstante zu erhalten:

#define BADKEY -1
#define A1 1
#define A2 2
#define B1 3
#define B2 4

typedef struct { char *key; int val; } t_symstruct;

static t_symstruct lookuptable[] = {
    { "A1", A1 }, { "A2", A2 }, { "B1", B1 }, { "B2", B2 }
};

#define NKEYS (sizeof(lookuptable)/sizeof(t_symstruct))

int keyfromstring(char *key)
{
    int i;
    for (i=0; i < NKEYS; i++) {
        t_symstruct *sym = lookuptable[i];
        if (strcmp(sym->key, key) == 0)
            return sym->val;
    }
    return BADKEY;
}

/* ... */
switch (keyfromstring(somestring)) {
case A1: /* ... */ break;
case A2: /* ... */ break;
case B1: /* ... */ break;
case B2: /* ... */ break;
case BADKEY: /* handle failed lookup */
}

Es gibt natürlich effizientere Möglichkeiten, dies zu tun. Wenn Sie Ihre Schlüssel sortiert halten, können Sie eine binäre Suche verwenden. Sie können auch eine Hashtabelle verwenden. Diese Dinge verändern Ihre Leistung auf Kosten der Wartung.

Sockel
quelle
7
Es ist viel schöner, eine Aufzählung anstelle einer Reihe von #defines für die Schlüssel zu verwenden, aber ansonsten ungefähr das Beste, was Sie tun können.
Craig Ringer
Das Inkrementieren ist falsch. lookuptable + i * sizeof (t_symstruct) ist nicht gleich lookuptable [i].
ASDF
@asdf So funktioniert Zeigerarithmetik in c. Die Größe von ist implizit.
Ijustlovemath
20

Meine bevorzugte Methode hierfür ist eine Hash-Funktion (von hier ausgeliehen ). Auf diese Weise können Sie die Effizienz einer switch-Anweisung auch dann nutzen, wenn Sie mit char * arbeiten:

#include "stdio.h"

#define LS 5863588
#define CD 5863276
#define MKDIR 210720772860
#define PWD 193502992

const unsigned long hash(const char *str) {
    unsigned long hash = 5381;  
    int c;

    while ((c = *str++))
        hash = ((hash << 5) + hash) + c;
    return hash;
}

int main(int argc, char *argv[]) {
    char *p_command = argv[1];
    switch(hash(p_command)) {
    case LS:
        printf("Running ls...\n");
        break;
    case CD:
        printf("Running cd...\n");
        break;
    case MKDIR:
        printf("Running mkdir...\n");
        break;
    case PWD:
        printf("Running pwd...\n");
        break;
    default:
        printf("[ERROR] '%s' is not a valid command.\n", p_command);
    }
}

Dieser Ansatz erfordert natürlich, dass die Hash-Werte für alle möglichen akzeptierten Zeichen im Voraus berechnet werden. Ich denke nicht, dass dies ein zu großes Problem ist. da die switch-Anweisung jedoch unabhängig davon mit festen Werten arbeitet. Ein einfaches Programm kann erstellt werden, um Zeichen durch die Hash-Funktion zu leiten und ihre Ergebnisse auszugeben. Diese Ergebnisse können dann wie oben beschrieben über Makros definiert werden.

Matthew Rasa
quelle
Willkommen bei Stack Overflow. Was Sie gezeigt haben, ist schön präsentiert und eine gute Idee, aber ... aber es unterscheidet sich nicht wesentlich von einigen der anderen Antworten - es gibt einige, die kleinere Varianten dieser Idee verwenden. Wenn Sie einer alten stabilen Frage eine neue Antwort hinzufügen, sollten Sie sehr sicher sein, dass Sie gute neue Informationen haben. Das ist meistens ein Wort der Vorsicht; Ich werde Sie sicherlich nicht dafür herabstimmen.
Jonathan Leffler
15

Ich denke, der beste Weg, dies zu tun, besteht darin, die "Erkennung" von der Funktionalität zu trennen:

struct stringcase { char* string; void (*func)(void); };

void funcB1();
void funcAzA();

stringcase cases [] = 
{ { "B1", funcB1 }
, { "AzA", funcAzA }
};

void myswitch( char* token ) {
  for( stringcases* pCase = cases
     ; pCase != cases + sizeof( cases ) / sizeof( cases[0] )
     ; pCase++ )
  {
    if( 0 == strcmp( pCase->string, token ) ) {
       (*pCase->func)();
       break;
    }
  }

}
xtofl
quelle
6

Es gibt eine Möglichkeit, die Zeichenfolgensuche schneller durchzuführen. Annahmen: Da es sich um eine switch-Anweisung handelt, kann ich davon ausgehen, dass sich die Werte zur Laufzeit nicht ändern.

Die Idee ist, qsort und bsearch der C stdlib zu verwenden.

Ich werde an xtofls Code arbeiten.

struct stringcase { char* string; void (*func)(void); };

void funcB1();
void funcAzA();

struct stringcase cases [] = 
{ { "B1", funcB1 }
, { "AzA", funcAzA }
};

struct stringcase work_cases* = NULL;
int work_cases_cnt = 0;

// prepare the data for searching
void prepare() {
  // allocate the work_cases and copy cases values from it to work_cases
  qsort( cases, i, sizeof( struct stringcase ), stringcase_cmp );
}

// comparator function
int stringcase_cmp( const void *p1, const void *p2 )
{
  return strcasecmp( ((struct stringcase*)p1)->string, ((struct stringcase*)p2)->string);
}

// perform the switching
void myswitch( char* token ) {
  struct stringcase val;
  val.string=token;
  void* strptr = bsearch( &val, work_cases, work_cases_cnt, sizeof( struct stringcase), stringcase_cmp );
  if (strptr) {
    struct stringcase* foundVal = (struct stringcase*)strptr;
    (*foundVal->func)();
    return OK;
  }
  return NOT_FOUND;
}
Dariusz
quelle
6

Um die obige Antwort von Phimueme zu ergänzen: Wenn Ihre Zeichenfolge immer aus zwei Zeichen besteht, können Sie aus den beiden 8-Bit-Zeichen ein 16-Bit-Int erstellen - und dieses aktivieren (um verschachtelte switch / case-Anweisungen zu vermeiden).

MikeBrom
quelle
Wenn Sie wirklich möchten, To add to Phimueme's answer abovekönnen Sie die Kommentarfunktion verwenden. :)
Zwiebel-Ritter
3
@Onion: Sie werden feststellen, dass MikeBrom derzeit nicht den Ruf hat, andere als seine eigenen Beiträge zu kommentieren und seine eigenen Fragen zu beantworten. Das heißt, @Mike "oben" ist in SO rutschig, da es keine zuverlässige Sortierreihenfolge gibt. Es ist besser, auf die Antwort wie "... in Phimuemes Antwort ..." zu verlinken (obwohl diese Antwort jetzt gelöscht wird und der Link nur für Benutzer mit mehr als 10.000 Reputation geeignet ist ).
dmckee --- Ex-Moderator Kätzchen
6

Ich habe eine Header-Datei veröffentlicht , um das Umschalten der Zeichenfolgen in C durchzuführen. Sie enthält eine Reihe von Makros, die den Aufruf von strcmp () (oder ähnlichem) verbergen, um ein switch-ähnliches Verhalten nachzuahmen. Ich habe es nur mit GCC unter Linux getestet, bin mir aber ziemlich sicher, dass es zur Unterstützung anderer Umgebungen angepasst werden kann.

BEARBEITEN: Fügen Sie den Code hier wie gewünscht hinzu

Dies ist die Header-Datei, die Sie einschließen sollten:

#ifndef __SWITCHS_H__
#define __SWITCHS_H__

#include <string.h>
#include <regex.h>
#include <stdbool.h>

/** Begin a switch for the string x */
#define switchs(x) \
    { char *__sw = (x); bool __done = false; bool __cont = false; \
        regex_t __regex; regcomp(&__regex, ".*", 0); do {

/** Check if the string matches the cases argument (case sensitive) */
#define cases(x)    } if ( __cont || !strcmp ( __sw, x ) ) \
                        { __done = true; __cont = true;

/** Check if the string matches the icases argument (case insensitive) */
#define icases(x)    } if ( __cont || !strcasecmp ( __sw, x ) ) { \
                        __done = true; __cont = true;

/** Check if the string matches the specified regular expression using regcomp(3) */
#define cases_re(x,flags) } regfree ( &__regex ); if ( __cont || ( \
                              0 == regcomp ( &__regex, x, flags ) && \
                              0 == regexec ( &__regex, __sw, 0, NULL, 0 ) ) ) { \
                                __done = true; __cont = true;

/** Default behaviour */
#define defaults    } if ( !__done || __cont ) {

/** Close the switchs */
#define switchs_end } while ( 0 ); regfree(&__regex); }

#endif // __SWITCHS_H__

Und so benutzt du es:

switchs(argv[1]) {
    cases("foo")
    cases("bar")
        printf("foo or bar (case sensitive)\n");
        break;

    icases("pi")
        printf("pi or Pi or pI or PI (case insensitive)\n");
        break;

    cases_re("^D.*",0)
        printf("Something that start with D (case sensitive)\n");
        break;

    cases_re("^E.*",REG_ICASE)
        printf("Something that start with E (case insensitive)\n");
        break;

    cases("1")
        printf("1\n");
        // break omitted on purpose

    cases("2")
        printf("2 (or 1)\n");
        break;

    defaults
        printf("No match\n");
        break;
} switchs_end;
Andrea Carron
quelle
Ich habe das Beispiel nicht durch Hinzufügen einer "Pause" bearbeitet, sondern die Tatsache hervorgehoben, dass Sie es weglassen können
Andrea Carron
das ist schöner! Bevor ich "sscanf" zum Abgleichen benutze, habe ich "regex.h" gelernt, was super mit String-Fällen zu tun hat :)
LinconFive
3

Wir können der if-else-Leiter nicht entkommen, um eine Zeichenfolge mit anderen zu vergleichen. Selbst ein normaler Switch-Case ist intern auch eine If-else-Leiter (für ganze Zahlen). Wir möchten möglicherweise nur das Switch-Case für String simulieren, können aber niemals die if-else-Leiter ersetzen. Die besten Algorithmen für den Zeichenfolgenvergleich können sich der Verwendung der Funktion strcmp nicht entziehen. Bedeutet, Zeichen für Zeichen zu vergleichen, bis eine Nichtübereinstimmung gefunden wird. Die Verwendung von if-else-Leiter und strcmp ist daher unvermeidlich.

DEMO

Und hier sind die einfachsten Makros, um den Schaltfall für Zeichenfolgen zu simulieren.

#ifndef SWITCH_CASE_INIT
#define SWITCH_CASE_INIT
    #define SWITCH(X)   for (char* __switch_p__ = X, int __switch_next__=1 ; __switch_p__ ; __switch_p__=0, __switch_next__=1) { {
    #define CASE(X)         } if (!__switch_next__ || !(__switch_next__ = strcmp(__switch_p__, X))) {
    #define DEFAULT         } {
    #define END         }}
#endif

Und Sie können sie als verwenden

char* str = "def";

SWITCH (str)
    CASE ("abc")
        printf ("in abc\n");
        break;
    CASE ("def")              // Notice: 'break;' statement missing so the control rolls through subsequent CASE's until DEFAULT 
        printf("in def\n");
    CASE ("ghi")
        printf ("in ghi\n");
    DEFAULT
        printf("in DEFAULT\n");
END

Ausgabe:

in def
in ghi
in DEFAULT

Unten ist die Verwendung von verschachtelten SWITCHs aufgeführt:

char* str = "def";
char* str1 = "xyz";

SWITCH (str)
    CASE ("abc")
        printf ("in abc\n");
        break;
    CASE ("def")                                
        printf("in def\n");
        SWITCH (str1)                           // <== Notice: Nested SWITCH
            CASE ("uvw")
                printf("in def => uvw\n");
                break;
            CASE ("xyz")
                printf("in def => xyz\n");
                break;
            DEFAULT
                printf("in def => DEFAULT\n");
        END
    CASE ("ghi")
        printf ("in ghi\n");
    DEFAULT
        printf("in DEFAULT\n");
END

Ausgabe:

in def
in def => xyz
in ghi
in DEFAULT

Hier ist die umgekehrte Zeichenfolge SWITCH, in der Sie eine Variable (anstelle einer Konstante) in der CASE-Klausel verwenden können:

char* str2 = "def";
char* str3 = "ghi";

SWITCH ("ghi")                      // <== Notice: Use of variables and reverse string SWITCH.
    CASE (str1)
        printf ("in str1\n");
        break;
    CASE (str2)                     
        printf ("in str2\n");
        break;
    CASE (str3)                     
        printf ("in str3\n");
        break;
    DEFAULT
        printf("in DEFAULT\n");
END

Ausgabe:

in str3
Ramu
quelle
"Auch ein normaler Switch-Case ist intern eine If-else-Leiter (für ganze Zahlen)", das stimmt nicht. Wenn möglich, generiert der Compiler eine Sprungtabelle, die viel effizienter ist. Siehe stackoverflow.com/a/14067661/4990392
Dada
2

So mache ich das im Allgemeinen.

void order_plane(const char *p)
{
    switch ((*p) * 256 + *(p+1))
    {
        case 0x4231 : /* B1 */
        {
           printf("Yes, order this bomber.  It's a blast.\n");
           break;
        }

        case 0x5354 : /* ST */
        {
            printf("Nah.  I just can't see this one.\n");
            break;
        }

        default :
        {
            printf("Not today.  Can I interest you in a crate of SAMs?\n";
        }
    }
}
EvilTeach
quelle
Interessant. Fehlt (wahrscheinlich nach Wahl) defensive Codierung. Und ich bewundere die zusätzlichen Zahnspangen für den Fall. Macht den Code so viel lesbarer (obwohl ich ägyptische Klammern für den Fall bevorzuge).
Dariusz
1
Übrigens können Sie in Fallbezeichnungen konstante Ausdrücke verwenden. case 'B'<<8+'1':würde dies klarer machen, denke ich, als 0x4231.
Jens
Ich würde ein Makro verwenden. #define twochar(a) (((uint16_t)a[1]<<8)|a[0])
v7d8dpo4
1

Das ist wie man es macht. Nein nicht wirklich.

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>


 #define p_ntohl(u) ({const uint32_t Q=0xFF000000;       \
                     uint32_t S=(uint32_t)(u);           \
                   (*(uint8_t*)&Q)?S:                    \
                   ( (S<<24)|                            \
                     ((S<<8)&0x00FF0000)|                \
                     ((S>>8)&0x0000FF00)|                \
                     ((S>>24)&0xFF) );  })

main (void)
{
    uint32_t s[0x40]; 
    assert((unsigned char)1 == (unsigned char)(257));
    memset(s, 0, sizeof(s));
    fgets((char*)s, sizeof(s), stdin);

    switch (p_ntohl(s[0])) {
        case 'open':
        case 'read':
        case 'seek':
            puts("ok");
            break;
        case 'rm\n\0':
            puts("not authorized");
            break;
        default:
            puts("unrecognized command");  
    }
    return 0;
}
user14554
quelle
3
Ich denke nicht, dass dies Standard C ist.
Johan Kotlinski
2
Die Unterstützung des Makros für gemischte Endianness oder eine Funktion bleibt dem Leser als Übung.
2
Es ist Standard C, aber nicht tragbar. Die Bytereihenfolge des Mehrbytezeichens ist "implementierungsabhängig" und muss nicht die Bytereihenfolge der Maschine widerspiegeln. Ich habe das einmal benutzt und mich verbrannt: Unter Solaris SPARC (Big Endian) verwendet GNU-C 3.4 eine andere Bytereihenfolge als Sunstudio 12.
Patrick Schlüter
@tristopia Sie haben natürlich Recht (so richtig wie möglich, nachdem Sie versucht haben, so etwas wirklich zu tun). Deshalb sollten wir stattdessen alle B verwenden.
Warum hast du dein Konto getötet?
1

Wenn es sich um eine 2-Byte-Zeichenfolge handelt, können Sie so etwas wie in diesem konkreten Beispiel tun, in dem ich ISO639-2-Sprachcodes einschalte.

    LANIDX_TYPE LanCodeToIdx(const char* Lan)
    {
      if(Lan)
        switch(Lan[0]) {
          case 'A':   switch(Lan[1]) {
                        case 'N': return LANIDX_AN;
                        case 'R': return LANIDX_AR;
                      }
                      break;
          case 'B':   switch(Lan[1]) {
                        case 'E': return LANIDX_BE;
                        case 'G': return LANIDX_BG;
                        case 'N': return LANIDX_BN;
                        case 'R': return LANIDX_BR;
                        case 'S': return LANIDX_BS;
                      }
                      break;
          case 'C':   switch(Lan[1]) {
                        case 'A': return LANIDX_CA;
                        case 'C': return LANIDX_CO;
                        case 'S': return LANIDX_CS;
                        case 'Y': return LANIDX_CY;
                      }
                      break;
          case 'D':   switch(Lan[1]) {
                        case 'A': return LANIDX_DA;
                        case 'E': return LANIDX_DE;
                      }
                      break;
          case 'E':   switch(Lan[1]) {
                        case 'L': return LANIDX_EL;
                        case 'N': return LANIDX_EN;
                        case 'O': return LANIDX_EO;
                        case 'S': return LANIDX_ES;
                        case 'T': return LANIDX_ET;
                        case 'U': return LANIDX_EU;
                      }
                      break;
          case 'F':   switch(Lan[1]) {
                        case 'A': return LANIDX_FA;
                        case 'I': return LANIDX_FI;
                        case 'O': return LANIDX_FO;
                        case 'R': return LANIDX_FR;
                        case 'Y': return LANIDX_FY;
                      }
                      break;
          case 'G':   switch(Lan[1]) {
                        case 'A': return LANIDX_GA;
                        case 'D': return LANIDX_GD;
                        case 'L': return LANIDX_GL;
                        case 'V': return LANIDX_GV;
                      }
                      break;
          case 'H':   switch(Lan[1]) {
                        case 'E': return LANIDX_HE;
                        case 'I': return LANIDX_HI;
                        case 'R': return LANIDX_HR;
                        case 'U': return LANIDX_HU;
                      }
                      break;
          case 'I':   switch(Lan[1]) {
                        case 'S': return LANIDX_IS;
                        case 'T': return LANIDX_IT;
                      }
                      break;
          case 'J':   switch(Lan[1]) {
                        case 'A': return LANIDX_JA;
                      }
                      break;
          case 'K':   switch(Lan[1]) {
                        case 'O': return LANIDX_KO;
                      }
                      break;
          case 'L':   switch(Lan[1]) {
                        case 'A': return LANIDX_LA;
                        case 'B': return LANIDX_LB;
                        case 'I': return LANIDX_LI;
                        case 'T': return LANIDX_LT;
                        case 'V': return LANIDX_LV;
                      }
                      break;
          case 'M':   switch(Lan[1]) {
                        case 'K': return LANIDX_MK;
                        case 'T': return LANIDX_MT;
                      }
                      break;
          case 'N':   switch(Lan[1]) {
                        case 'L': return LANIDX_NL;
                        case 'O': return LANIDX_NO;
                      }
                      break;
          case 'O':   switch(Lan[1]) {
                        case 'C': return LANIDX_OC;
                      }
                      break;
          case 'P':   switch(Lan[1]) {
                        case 'L': return LANIDX_PL;
                        case 'T': return LANIDX_PT;
                      }
                      break;
          case 'R':   switch(Lan[1]) {
                        case 'M': return LANIDX_RM;
                        case 'O': return LANIDX_RO;
                        case 'U': return LANIDX_RU;
                      }
                      break;
          case 'S':   switch(Lan[1]) {
                        case 'C': return LANIDX_SC;
                        case 'K': return LANIDX_SK;
                        case 'L': return LANIDX_SL;
                        case 'Q': return LANIDX_SQ;
                        case 'R': return LANIDX_SR;
                        case 'V': return LANIDX_SV;
                        case 'W': return LANIDX_SW;
                      }
                      break;
          case 'T':   switch(Lan[1]) {
                        case 'R': return LANIDX_TR;
                      }
                      break;
          case 'U':   switch(Lan[1]) {
                        case 'K': return LANIDX_UK;
                        case 'N': return LANIDX_UN;
                      }
                      break;
          case 'W':   switch(Lan[1]) {
                        case 'A': return LANIDX_WA;
                      }
                      break;
          case 'Z':   switch(Lan[1]) {
                        case 'H': return LANIDX_ZH;
                      }
                      break;
        }
      return LANIDX_UNDEFINED;
    }

LANIDX_ * sind konstante Ganzzahlen, die zum Indizieren in Arrays verwendet werden.

Patrick Schlüter
quelle
0

Unter der Annahme einer geringen Endianness und Größe von (char) == 1 könnten Sie dies tun (so etwas wurde von MikeBrom vorgeschlagen).

char* txt = "B1";
int tst = *(int*)txt;
if ((tst & 0x00FFFFFF) == '1B')
    printf("B1!\n");

Es könnte für den BE-Fall verallgemeinert werden.

ruslik
quelle
2
Tu das nicht! Dies kann eine Ausnahme "Datenausrichtung" verursachen. Es kann nicht garantiert werden, dass char * txt auf eine Adresse verweist, die den Ausrichtungsanforderungen von int entspricht.
Harper
@R er hat danach gefragt. @harper ist es bei x86 nicht der Fall.
Ruslik
Niklas hat nicht nach x86 gefragt. Und da Sie den Big-Endian-Fall erwähnt haben, sprechen Sie nicht ausschließlich die x86-Umgebung an. Damit'
Harper
Darüber hinaus sind Multi-Byte-Zeichen nicht unbedingt in der Reihenfolge der Maschinenbytes enthalten. Siehe meinen Kommentar zur Antwort von jbcreix.
Patrick Schlüter
0

Funktionszeiger sind eine gute Möglichkeit, dies zu tun, z

result = switchFunction(someStringKey); //result is an optional return value

... ruft eine Funktion auf, die Sie mit der Zeichenfolgentaste festgelegt haben (eine Funktion pro Fall):

setSwitchFunction("foo", fooFunc);
setSwitchFunction("bar", barFunc);

Verwenden Sie eine bereits vorhandene Implementierung von Hashmap / Tabelle / Wörterbuch wie khash, geben Sie diesen Zeiger auf eine Funktion innerhalb von zurück switchFunction()und führen Sie sie aus (oder geben Sie sie einfach von zurück switchFunction()und führen Sie sie selbst aus). Wenn die Map-Implementierung dies nicht speichert, verwenden Sie uint64_tstattdessen ein, das Sie entsprechend in einen Zeiger umwandeln.

Ingenieur
quelle
@ eri0o Wenn du es für anständig hältst, warum nicht positiv bewerten? Der ursprüngliche Downvoter ist längst verschwunden.
Ingenieur
-2

Hallo, das ist der einfache und schnelle Weg, wenn Sie diesen Fall haben:

[Schneller Modus]

int concated;
char ABC[4]="";int a=1,b=4,c=2;            //char[] Initializing
ABC<-sprintf(ABC,"%d%d%d",a,b,c);          //without space between %d%d%d
printf("%s",ABC);                          //value as char[] is =142
concated=atoi(ABC);                        //result is 142 as int, not 1,4,2 (separeted)

//now use switch case on 142 as an integer and all possible cases

[ERKLÄRTER Modus]

Zum Beispiel: Ich habe viele Menüs, jede Auswahl im 1. Menü führt Sie zum 2. Menü, dasselbe mit dem 2. Menü und dem 3. Menü. Aber die Optionen sind unterschiedlich, so dass Sie wissen, dass der Benutzer endgültig gewählt hat. Beispiel:

Menü 1: 1 ==> Menü 2: 4 ==> Menü 3: 2 (...) Die Auswahl ist 142. Andere Fälle: 111,141,131,122 ...

Sollution: Speichern Sie die erste 1. in a, 2. in b, 3. auf c. a = 1, b = 4, c = 2

 char ABC[4]="";
 ABC<-sprintf(ABC,"%d%d%d",a,b,c);              //without space between %d%d%d
 printf("%s",ABC);                              //value as char[]=142

      //now you want to recover your value(142) from char[] to int as  int value 142

 concated=atoi(ABC);                            //result is 142 as int, not 1,4,2 (separeted)
abdull benlamine
quelle