Jak mogę porównać ciągi w języku C za pomocą instrukcji „switch”?

84

W C jest switchkonstrukt, który umożliwia wykonanie różnych warunkowych gałęzi kodu na podstawie testowej wartości całkowitej, np.

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

Jak można uzyskać takie samo zachowanie (tj. Uniknąć tzw. „ if- elsedrabiny”) dla wartości typu string, tj. A char *?

Niklas
źródło
Co masz na myśli mówiąc „włącz”?
kennytm
Proszę przeformułować, aby pytanie było jasne, co faktycznie próbujesz zrobić (lub o co pytasz).
Šimon Tóth,
8
OP prawdopodobnie chce użyć łańcucha jako parametru instrukcji switch. O ile wiem, nie jest to możliwe.
dandan78

Odpowiedzi:

101

Jeśli masz na myśli, jak napisać coś podobnego do tego:

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

Wtedy rozwiązaniem kanonicznym w C jest użycie drabiny if-else:

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
źródło
1
Właściwie problem w tym, że mam już włącznik na int iw szczególnym przypadku mam wartości „B1” i „B2”, które chcę użyć w tym samym przełączniku. Jedynym sposobem jest jakoś przekonwertować wartości „B1” i „B2” i użyć ich jako int !!?
Niklas
2
@Niklas: To ważna informacja na Twoje pytanie. Czy możesz zaktualizować swoje pytanie i wyjaśnić (jeśli to możliwe za pomocą jakiegoś (pseudo) kodu), co próbujesz zrobić?
Bart van Ingen Schenau
4
@Niklas: Powinieneś wyjaśnić swoje pytanie: jak u licha „B1” i „B2” mogą być specjalnym przypadkiem int?
Edgar Bonet,
1
#define A 1 #define B 2 #define C S1 #define D S2 i te wartości są tym, czego chcę użyć w moim przełączniku. Takie proste :-)
Niklas
5
@Niklas: Definicje nie są ciągami. Jeśli definicja dotyczy liczby, możesz jej użyć bezpośrednio w swoim przełączniku w ten sposób switch (something) { case A: /*...*/ break; case B: /*...*/ break; }.
Bart van Ingen Schenau
45

Jeśli masz wiele spraw i nie chcesz pisać wielu strcmp()telefonów, możesz zrobić coś takiego:

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

Musisz tylko upewnić się, że twoja funkcja skrótu nie ma kolizji w zestawie możliwych wartości dla ciągu.

Edgar Bonet
źródło
8
„upewnij się, że funkcja skrótu nie powoduje kolizji w zbiorze możliwych wartości ciągu”. - Czy istnieje taka funkcja skrótu dla alfabetu [a-zA-Z0-9_]? Jakiś przykład?
Arun
8
@ArunSaha: Oczywiście nie dla dowolnych kombinacji takich znaków.
Edgar Bonet
3
Jeśli używasz kluczy łańcuchowych o stałej długości, możesz je przekształcić w unikalne liczby całkowite; kolizje nie są możliwe.
Inżynier,
@ArcaneEngineer Um ... czy to nie jest dokładny problem, który próbuje rozwiązać pytanie? W jaki sposób, mając tylko ciąg znaków, wybrałbyś liczbę całkowitą, która do niego pasuje? „użyj przełącznika lub drabiny if / else” A może masz na myśli coś bardzo krótkiego, np. 4 znaki?
ebyrob
@ebyrob Miałem na myśli wszystko, co można porównać w szybkiej operacji, na przykład 2 64-bitowe, uintktórych bity są traktowane jako 8 1-bajtowych ASCII char. Zaimplementowałem to jakiś czas temu, dla porównań kluczy w tablicy skrótów w C. W ten sposób eliminujesz potrzebę mieszania lub wiader. Problem pojawia się, gdy musisz przekroczyć 64 bity; następnie płacisz koszt za warunki warunkowe, wykonując pętlę po każdym zestawie 8 charsekund w całym ciągu. Chyba że rozwiniesz pętlę, jeśli znasz maksymalny rozmiar kluczy. To świetna równowaga.
Inżynier
39

Nie da się tego zrobić w C. Istnieje wiele różnych podejść. Zwykle najprościej jest zdefiniować zestaw stałych, które reprezentują ciągi znaków i wyszukać je po łańcuchu, aby uzyskać stałą:

#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 */
}

Oczywiście są na to skuteczniejsze sposoby. Jeśli przechowujesz klucze posortowane, możesz użyć wyszukiwania binarnego. Możesz też użyć hashy. Te rzeczy zmieniają wydajność kosztem konserwacji.

cokół
źródło
7
O wiele przyjemniej jest użyć wyliczenia zamiast zestawu #defines dla kluczy, ale poza tym to najlepsze, co możesz zrobić.
Craig Ringer
przyrost jest nieprawidłowy. lookuptable + i * sizeof (t_symstruct) nie jest równe lookuptable [i].
asdf
@asdf Tak działa arytmetyka wskaźników w c. Rozmiar sizeof jest niejawny.
ijustlovemath
20

Moją preferowaną metodą jest użycie funkcji skrótu (zapożyczonej stąd ). Pozwala to wykorzystać wydajność instrukcji switch nawet podczas pracy z znakami *:

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

Oczywiście to podejście wymaga, aby wartości skrótu dla wszystkich możliwych akceptowanych znaków * zostały obliczone z wyprzedzeniem. Nie sądzę, żeby to był zbyt duży problem; jednakże, ponieważ instrukcja switch działa niezależnie od stałych wartości. Prosty program może przepuścić znaki * przez funkcję skrótu i ​​wypisać ich wyniki. Wyniki te można następnie zdefiniować za pomocą makr, tak jak to zrobiłem powyżej.

Matthew Rasa
źródło
Witamy w Stack Overflow. To, co pokazałeś, jest ładnie przedstawione i jest dobrym pomysłem, ale… ale nie różni się zbytnio od niektórych innych odpowiedzi - jest kilka, które wykorzystują pomniejsze warianty tego pomysłu. Jeśli dodasz nową odpowiedź do starego stabilnego pytania, powinieneś być bardzo pewien, że masz dobre nowe informacje. To głównie słowo przestrogi; Z pewnością nie zamierzam cię za to głosować.
Jonathan Leffler
16

Myślę, że najlepszym sposobem na to jest oddzielenie `` rozpoznawania '' od funkcjonalności:

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
źródło
8

Opublikowałem plik nagłówkowy służący do przełączania ciągów znaków w C. Zawiera zestaw makr, które ukrywają wywołanie funkcji strcmp () (lub podobnej) w celu naśladowania zachowania podobnego do przełącznika. Testowałem go tylko z GCC w Linuksie, ale jestem pewien, że da się go dostosować do obsługi innego środowiska.

EDYCJA: dodałem kod tutaj, zgodnie z żądaniem

To jest plik nagłówkowy, który powinieneś dołączyć:

#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__

A tak z tego korzystasz:

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
źródło
Zredagowałem przykład nie dodając „przerwy”, ale podkreślając fakt, że można go pominąć
Andrea Carron
1
to jest ładniejsze! Zanim użyję „sscanf” do dopasowania, nauczyłem się „regex.h”, co jest super do zrobienia z przypadkami łańcuchowymi :)
LinconFive
Cóż za piękne rozwiązanie, dobra czytelność i znacznie większa funkcjonalność w porównaniu do przełącznika / obudowy - dzięki! Nie zapomnij o "switchs_end:" po zamykającym nawiasie.
Achim
6

Istnieje sposób na szybsze wyszukiwanie ciągów. Założenia: skoro mówimy o instrukcji switch, mogę założyć, że wartości nie będą się zmieniać w czasie wykonywania.

Chodzi o to, aby użyć qsort i bsearch z biblioteki standardowej C.

Będę pracował nad kodem xtofl.

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
źródło
6

Aby dodać do powyższej odpowiedzi Phimueme, jeśli twój ciąg składa się zawsze z dwóch znaków, możesz zbudować 16-bitowy int z dwóch 8-bitowych znaków - i włączyć to (aby uniknąć zagnieżdżonych instrukcji switch / case).

MikeBrom
źródło
Jeśli naprawdę chcesz To add to Phimueme's answer above, możesz skorzystać z funkcji komentowania. :)
Onion-Knight
3
@Onion: Zauważysz, że MikeBrom nie ma obecnie reputacji komentowania postów innych niż jego własne i odpowiedzi na własne pytania. To powiedziawszy, @Mike "powyżej" jest śliskie w SO, ponieważ nie ma niezawodnego porządku sortowania. Lepiej jest podać link do odpowiedzi, na przykład „… w odpowiedzi Phimueme …” (chociaż ta odpowiedź jest teraz usuwana, a łącze jest dobre tylko dla użytkowników o reputacji ponad 10 000 ).
dmckee --- ex-moderator kitten
3

Nie możemy uciec od drabiny if-else w celu porównania łańcucha z innymi. Nawet zwykły przypadek przełącznika jest wewnętrznie drabiną if-else (dla liczb całkowitych). Możemy chcieć tylko zasymulować obudowę przełącznika dla łańcucha, ale nigdy nie możemy zastąpić drabiny if-else. Najlepszy z algorytmów do porównywania ciągów znaków nie może uciec przed użyciem funkcji strcmp. Oznacza porównywanie znaków do momentu znalezienia niezgodności. Dlatego użycie drabiny if-else i strcmp jest nieuniknione.

PRÓBNY

A oto najprostsze makra do symulacji przełącznika dla łańcuchów.

#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

Możesz ich używać jako plików

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

Wynik:

in def
in ghi
in DEFAULT

Poniżej zagnieżdżone użycie SWITCH:

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

Wynik:

in def
in def => xyz
in ghi
in DEFAULT

Oto odwrócony ciąg SWITCH, w którym w klauzuli CASE można użyć zmiennej (zamiast stałej):

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

Wynik:

in str3
Ramu
źródło
„Nawet zwykły przypadek przełącznika jest wewnętrzną drabiną if-else (dla liczb całkowitych)” to nieprawda. Jeśli to możliwe, kompilator wygeneruje tablicę skoków, która będzie znacznie wydajniejsza. Zobacz stackoverflow.com/a/14067661/4990392
Dada
2

Generalnie tak to robię.

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
źródło
Ciekawy. Brakuje (prawdopodobnie z wyboru) kodowania obronnego. Podziwiam dodatkowe szelki w etui. Sprawia, że ​​kod jest znacznie bardziej czytelny (chociaż wolę egipskie nawiasy klamrowe).
Dariusz
1
Przy okazji, możesz używać stałych wyrażeń w etykietach przypadków. case 'B'<<8+'1':uczyniłoby to jaśniejszym, jak sądzę, niż 0x4231.
Jens
Użyłbym makra. #define twochar(a) (((uint16_t)a[1]<<8)|a[0])
v7d8dpo4
1

Tak to się robi. Nie, nie bardzo.

#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;
}
cykli user14554
źródło
3
Nie sądzę, żeby to było standardowe C.
Johan Kotlinski
2
Wykonanie makra z obsługą mieszanego endianizmu lub funkcji pozostawia się jako ćwiczenie dla czytelnika.
2
Jest to standardowe C, ale nie przenośne. Kolejność bajtów wielobajtowego znaku jest zależna od implementacji i nie musi odzwierciedlać kolejności bajtów komputera. Użyłem tego raz i się spaliłem: na Solarisie SPARC (big endian) GNU-C 3.4 używa innej kolejności bajtów niż Sunstudio 12.
Patrick Schlüter
@tristopia Masz oczywiście rację (tak jak można mieć rację, próbując zrobić coś takiego naprawdę). Dlatego wszyscy powinniśmy zamiast tego używać B.
Dlaczego zabiłeś swoje konto?
1

Jeśli jest to ciąg 2-bajtowy, możesz zrobić coś podobnego do tego konkretnego przykładu, w którym włączam kody językowe ISO639-2.

    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_ * będące stałymi liczbami całkowitymi używanymi do indeksowania tablic.

Patrick Schlüter
źródło
0

Zakładając little endianness i sizeof (char) == 1, można to zrobić (coś takiego zasugerował MikeBrom).

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

Można to uogólnić dla przypadku BE.

ruslik
źródło
2
Nie rób tego! Może to spowodować wyjątek „wyrównania danych”. Nie ma gwarancji, że char * txt wskazuje na adres, który spełnia wymagania dotyczące wyrównania int.
harper,
@R poprosił o to. @harper tak nie jest w przypadku x86.
ruslik
Niklas nie poprosił o x86. A ponieważ wspomniałeś o przypadku big endian, nie zajmujesz się wyłącznie środowiskiem x86. Tak więc ”
harper
Co więcej, znaki wielobajtowe nie muszą być koniecznie uporządkowane według bajtów maszynowych. Zobacz mój komentarz do odpowiedzi jbcreix.
Patrick Schlüter
0

Wskaźniki funkcji to świetny sposób, aby to zrobić, np

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

... to wywołuje funkcję, którą ustawiłeś klawiszem string (jedna funkcja na przypadek):

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

Użyj wcześniej istniejącej implementacji hashmap / tabeli / słownika, takiej jak khash, zwróć ten wskaźnik do funkcji znajdującej się wewnątrz switchFunction()i wykonaj ją (lub po prostu zwróć ją switchFunction()i wykonaj samodzielnie). Jeśli implementacja mapy nie przechowuje tego, po prostu użyj uint64_tzamiast tego rzutowania odpowiednio do wskaźnika.

Inżynier
źródło
@ eri0o Jeśli uważasz, że to przyzwoite, dlaczego nie zagłosować za nim? Pierwotny przeciwnik dawno już minął.
Inżynier
-2

Cześć, to jest łatwy i szybki sposób, jeśli masz ten przypadek:

[Szybki tryb]

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

[OBJAŚNIENIE Tryb]

na przykład: mam wiele menu, każdy wybór z pierwszego menu przenosi cię do drugiego menu, to samo z drugim menu i trzecim menu. ale opcje są różne, więc wiesz, że użytkownik ostatecznie wybrał. przykład:

menu 1: 1 ==> menu 2: 4 ==> menu 3: 2 (...) do wyboru 142. inne przypadki: 111,141,131,122 ...

rozwiązanie: zapisz pierwszy pierwszy w a, drugi w b, trzeci w 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
źródło