103

In C there is a switch construct which enables one to execute different conditional branches of code based on an test integer value, e.g.,

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

How is it possible to obtain the same behavior (i.e. avoid the so-called "if-else ladder") for a string value, i.e., a char *?

Edwin Pratt
  • 745
  • 9
  • 19
Niklas
  • 1,117
  • 2
  • 8
  • 6
  • What do you mean by "switch on"? – kennytm Oct 25 '10 at 13:12
  • Please reformulate so that the question makes clear what you are actually trying to do (or asking). – Šimon Tóth Oct 25 '10 at 13:13
  • 9
    The OP probably wants to use a string as the paramater of a switch statement. As far as I know, this is not possible. – dandan78 Oct 25 '10 at 13:14
  • You cannot use strings in switch statements, but to avoid checking one string at a time with a naive else if ladder, I suggest a [binary search](https://en.wikipedia.org/wiki/Binary_search_algorithm) – user16217248 Mar 01 '22 at 17:08

15 Answers15

130

If you mean, how to write something similar to this:

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

Then the canonical solution in C is to use an if-else ladder:

if (strcmp(string, "B1") == 0) 
{
  // do something
} 
else if (strcmp(string, "xxx") == 0)
{
  // do something else
}
/* more else if clauses */
else /* default: */
{
}
dylnmc
  • 3,570
  • 4
  • 22
  • 40
Bart van Ingen Schenau
  • 15,018
  • 4
  • 30
  • 41
  • 1
    Actually, the problem is that I already have a switch on int and in a special case I have the value "B1" and "B2" which I want to use in same switch. The Only way is to somehow convert the "B1" and "B2" values and use them as int!!? – Niklas Oct 25 '10 at 13:26
  • 3
    @Niklas: This is important information for your question. Can you update your question and explain (if possible with some (pseudo-)code) what you are trying to do? – Bart van Ingen Schenau Oct 25 '10 at 13:32
  • 5
    @Niklas: You should clarify your question: how on earth could "B1" and "B2" be a special case of an int? – Edgar Bonet Oct 25 '10 at 13:35
  • @Niklas: if you need to make decisions based on different data types, then you will have to change your control structure. The easiest and most straightforward is to use an if-else chain. Alternately, instead of switching on a variable, you can switch on a function that will take an `int` and `char *` as arguments and return an `int` value based on those inputs. – John Bode Oct 25 '10 at 14:03
  • Edgar: Maybe he means 0xB1 and 0xB2? – Eyal Oct 25 '10 at 14:39
  • Gooosh, this is what I mean. I have these defines (NOOO, I can't change these defines) – Niklas Oct 25 '10 at 19:13
  • 1
    #define A 1 #define B 2 #define C S1 #define D S2 and these values are what I want to use in my switch. So simple :-) – Niklas Oct 25 '10 at 19:15
  • 6
    @Niklas: Defines are not strings. If the define is for a number, you can use it directly in your switch like this `switch (something) { case A: /*...*/ break; case B: /*...*/ break; }`. – Bart van Ingen Schenau Oct 26 '10 at 08:54
57

If you have many cases and do not want to write a ton of strcmp() calls, you could do something like:

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

You just have to make sure your hash function has no collisions inside the set of possible values for the string.

Edgar Bonet
  • 3,296
  • 14
  • 18
  • 13
    "make sure your hash function has no collisions inside the set of possible values for the string." -- Does such a hash function exists for the alphabet `[a-zA-Z0-9_]`? Any example? – Arun Oct 26 '10 at 04:17
  • 11
    @ArunSaha: Obviously not for _arbitrary combinations_ of such characters. – Edgar Bonet Oct 26 '10 at 06:21
  • 4
    If you use fixed length string keys, you can convert them each into unique integers; no collisions possible. – Engineer Sep 16 '15 at 08:41
  • @ArcaneEngineer Um... isn't that the exact problem the question is trying to solve? How, given the string only, would you pick out an integer to go with it? "use a switch or if/else ladder" Or maybe you mean something very short like 4 characters? – ebyrob Feb 02 '18 at 16:24
  • 1
    @ebyrob I meant anything comparable in a quick op, such as 2 64-bit `uint`s whose bits are treated as 8 1-byte ASCII `char`s. I implemented this a while ago, for key comparisons within a hash table in C. You thus eradicate the need for any hashing or buckets. The problem comes in where you need to exceed 64 bits; you then pay the cost for conditionals as you loop over each set of 8 `char`s in the full string. Unless you unroll the loop, if you know the max size of keys. It's a fine balancing act. – Engineer Feb 02 '18 at 16:34
  • @ArcaneEngineer That's actually brilliant, should be an answer here... ;-) – ebyrob Feb 02 '18 at 16:44
  • String switching was introduced as a language feature in Java 7. The compiler performs a code transformation involving a hash function, just like your own example. – Nayuki Mar 13 '18 at 19:27
  • [Qt has built-in support for switching strings like this](https://stackoverflow.com/a/25873662/995714), probably via a hash function under the hood – phuclv Oct 17 '18 at 08:40
  • 1
    A brilliant implementation of this, without manually calculating the hash: http://www.heeden.nl/statichashc.htm – lkanab Mar 21 '21 at 08:27
  • @lkanab No hash function that takes an arbitrary C string and returns an integral value can ever be guaranteed to not produce collisions. In fact, such a function [**must** produce collisions](https://en.wikipedia.org/wiki/Pigeonhole_principle). KISS - just use an `if-else if` ladder. – Andrew Henle Feb 13 '22 at 23:03
45

There is no way to do this in C. There are a lot of different approaches. Typically the simplest is to define a set of constants that represent your strings and do a look up by string on to get the constant:

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

There are, of course, more efficient ways to do this. If you keep your keys sorted, you can use a binary search. You could use a hashtable too. These things change your performance at the expense of maintenance.

asdf
  • 766
  • 1
  • 10
  • 27
plinth
  • 47,047
  • 11
  • 77
  • 120
22

My preferred method for doing this is via a hash function (borrowed from here). This allows you to utilize the efficiency of a switch statement even when working with char *'s:

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

Of course, this approach requires that the hash values for all possible accepted char *'s are calculated in advance. I don't think this is too much of an issue; however, since the switch statement operates on fixed values regardless. A simple program can be made to pass char *'s through the hash function and output their results. These results can then be defined via macros as I have done above.

Community
  • 1
  • 1
Matthew Rasa
  • 570
  • 4
  • 10
  • Welcome to Stack Overflow. What you've shown is nicely presented and a good idea, but … but it isn't all that distinctively different from some of the other answers — there are several that use minor variants on this idea. If you add a new answer to an old stable question, you should be very sure you have good new information. That's mostly a word of caution; I'm certainly not about to down-vote you for this. – Jonathan Leffler May 09 '16 at 17:31
  • @JonathanLeffler I think this is the best answer. There is nothing wrong with posting a complete solution. All the other solutions should have been deleted given this one is the best. The if-else chain solution (currently with the best rank) does not address the intent of the original question. It has a high score just because it was posted earlier. If those who voted early compared this one and that one, they would rank this one higher. Stackoverflow should have a way to depreciate older votes. Otherwise, it would cause this weird situation in which the best solution is not ranked the top. – user15502206 May 03 '21 at 22:01
  • 1
    *This allows you to utilize the efficiency of a switch statement even when working with char *'s* There's not much if any efficiency gained over and `if-else if...` ladder of `strcmp()` calls unless the strings being compared contain relatively long sequences of common initial characters. If the strings all differ within the first 4-8 characters, a properly optimized `strcmp()` will compare the strings with a single operation, whereas with a hash function the entire string must be hashed every time. – Andrew Henle Feb 13 '22 at 23:07
18

I think the best way to do this is separate the 'recognition' from the functionality:

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
  • 39,598
  • 12
  • 100
  • 188
12

I have published a header file to perform the switch on the strings in C. It contains a set of macro that hide the call to the strcmp() (or similar) in order to mimic a switch-like behaviour. I have tested it only with GCC in Linux, but I'm quite sure that it can be adapted to support other environment.

EDIT: added the code here, as requested

This is the header file you should include:

#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 *ss__sw = (x); bool ss__done = false; bool ss__cont = false; \
        regex_t ss__regex; regcomp(&ss__regex, ".*", 0); do {

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

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

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

/** Default behaviour */
#define defaults    } if ( !ss__done || ss__cont ) {

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

#endif // __SWITCHS_H__

And this is how you use it:

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
  • 941
  • 13
  • 21
  • I edited the example not by adding a "break", but highlighting the fact that you can omit it – Andrea Carron Feb 12 '20 at 14:18
  • 1
    that is nicer! Before I use "sscanf" to match, learnt "regex.h", which is super to do with string cases :) – LinconFive Feb 13 '20 at 02:47
  • What a beautiful solution, good readable and much more functionality compared to a switch/case - Thanks! Don't forget the "switchs_end:" after closing bracket. – Achim Sep 11 '20 at 18:10
  • Note, though, that identifiers that begin with a double underscore, such as `__sw`, are [reserved identifiers](https://port70.net/~nsz/c/c11/n1570.html#7.1.3): "All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use." – Andrew Henle Feb 13 '22 at 23:09
  • @AndrewHenle thanks for the info. I update the code adding the prefix "ss" (switch string) – Andrea Carron Mar 22 '22 at 09:04
6

There is a way to perform the string search faster. Assumptions: since we are talking about a switch statement, I can assume that the values won't be changing during runtime.

The idea is to use the C stdlib's qsort and bsearch.

I'll be working on xtofl's code.

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
  • 20,650
  • 8
  • 71
  • 109
6

To add to Phimueme's answer above, if your string is always two characters, then you can build a 16-bit int out of the two 8-bit characters - and switch on that (to avoid nested switch/case statements).

royhowie
  • 10,805
  • 14
  • 48
  • 67
MikeBrom
  • 139
  • 6
  • If you really wish to `To add to Phimueme's answer above`, then feel free to use the comment function. :) – Onion-Knight Oct 25 '10 at 14:29
  • 3
    @Onion: You'll note that MikeBrom does not currently have the reputation to comment on posts other than his own and answers to his own questions. That said, @Mike "above" is slippery in SO, becuase there is no reliable sort-order. Better to link to the answer like *"... [in Phimueme's answer](http://stackoverflow.com/questions/4014827/best-way-to-switch-on-a-string-in-c/4014887#4014887) ..."* (though that answer is deleted now, and the link is only good for user with 10k+ reputation). – dmckee --- ex-moderator kitten Oct 25 '10 at 21:01
3

We cannot escape if-else ladder in order to compare a string with others. Even regular switch-case is also an if-else ladder (for integers) internally. We might only want to simulate the switch-case for string, but can never replace if-else ladder. The best of the algorithms for string comparison cannot escape from using strcmp function. Means to compare character by character until an unmatch is found. So using if-else ladder and strcmp are inevitable.

DEMO

And here are simplest macros to simulate the switch-case for strings.

#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

And you can use them as

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

Output:

in def
in ghi
in DEFAULT

Below is nested SWITCH usage:

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

Output:

in def
in def => xyz
in ghi
in DEFAULT

Here is reverse string SWITCH, where in you can use a variable (rather than a constant) in CASE clause:

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

Output:

in str3
Ramu
  • 117
  • 3
  • "Even regular switch-case is also an if-else ladder (for integers) internally" that's not true. If possible, the compiler will generate a jump table, which will be much more efficient. See https://stackoverflow.com/a/14067661/4990392 – Dada Aug 14 '20 at 08:57
2

This is generally how I do it.

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
  • 27,432
  • 21
  • 83
  • 138
  • Interesting. Lacks (probably by choice) defensive coding. And I admire the additional braces in case. Makes the code so much more readable (though I prefer egyptian braces for case). – Dariusz May 20 '13 at 10:01
  • 1
    BTW, you can use constant expressions in case labels. `case 'B'<<8+'1':` would make this clearer, I think, than 0x4231. – Jens May 20 '13 at 11:25
  • I would use a macro. `#define twochar(a) (((uint16_t)a[1]<<8)|a[0])` – v7d8dpo4 Nov 09 '16 at 05:17
1

If it is a 2 byte string you can do something like in this concrete example where I switch on ISO639-2 language codes.

    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_* being constant integers used to index in arrays.

Patrick Schlüter
  • 10,935
  • 1
  • 40
  • 47
1

This is how you do it. No, not really.

#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;
}
  • 3
    I don't think this is standard C. – Johan Kotlinski Nov 12 '10 at 13:43
  • 2
    Making the macro support mixed endianness, or a function is left as an exercise for the reader. –  Nov 12 '10 at 15:18
  • 3
    It is standard C, but not portable. The byte order of the multi-byte char is 'implementation dependend' and doesn't need to reflect the machines byte order. I used that once and got burnt: on Solaris SPARC (big endian) GNU-C 3.4 uses a different byte order than Sunstudio 12. – Patrick Schlüter Aug 28 '12 at 21:47
  • @tristopia You are right of course(as right as one can be after attempting to do something like this for real). This is why we should be all using B instead. –  Aug 29 '12 at 16:43
0

Assuming little endianness and sizeof(char) == 1, you could do that (something like this was suggested by MikeBrom).

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

It could be generalized for BE case.

ruslik
  • 14,334
  • 1
  • 35
  • 38
  • 3
    Dont do that! This may cause a "data alignment" exception. It's not guaranteed that the char* txt points to an address, that matches alignment requirements of int. – harper Oct 25 '10 at 14:09
  • @R he asked for that. @harper it's not the case for x86. – ruslik Oct 25 '10 at 14:21
  • Niklas didn't ask for x86. And since you mentioned the big endian case, you don't address exclusively the x86 environment. So that' – harper Oct 26 '10 at 04:26
  • 1
    Furthermore, multi-byte chars are not necesserly in machine byte order. See my comment to jbcreix answer. – Patrick Schlüter Aug 28 '12 at 21:49
0

Function pointers are a great way to do this, e.g.

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

...this calls a function that you have set by string key (one function per case):

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

Use a pre-existing hashmap/table/dictionary implementation such as khash, return that pointer to a function inside of switchFunction(), and execute it (or just return it from switchFunction() and execute it yourself). If the map implementation doesn't store that, just use a uint64_t instead that you cast accordingly to a pointer.

Engineer
  • 7,990
  • 7
  • 60
  • 99
-2

Hi this is the easy and fast way if you have this case :

[QUICK Mode]

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

[EXPLAINED Mode]

for example : i have many menus, each choice on the 1st menu takes u to the 2nd menu, the same thing with the 2nd menu and the 3rd menu.but the Options are diferent so you know that the user has choised finnaly. exemple :

menu 1: 1 ==> menu 2: 4==> menu 3: 2 (...)the choice is 142. other cases : 111,141,131,122...

sollution: store the first 1st in a,2nd in b,3rd on 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)