Làm cách nào để so sánh các chuỗi trong C bằng câu lệnh `switch`?


84

Trong C có một switchcấu trúc cho phép người ta thực thi các nhánh có điều kiện khác nhau của mã dựa trên một giá trị số nguyên thử nghiệm, ví dụ:

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

Làm thế nào để có thể có được cùng một hành vi (tức là tránh cái gọi là " if- elsebậc thang") cho một giá trị chuỗi, tức là, a char *?


Ý bạn là gì khi "bật"?
kennytm

Hãy định dạng lại để câu hỏi làm rõ những gì bạn thực sự đang cố gắng làm (hoặc yêu cầu).
Šimon Tóth

8
OP có thể muốn sử dụng một chuỗi làm tham số của một câu lệnh switch. Theo như tôi biết, điều này là không thể.
dandan78

Câu trả lời:


101

Nếu bạn muốn nói, làm thế nào để viết một cái gì đó tương tự như thế này:

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

Sau đó, giải pháp chính tắc trong C là sử dụng thang if-else:

if (strcmp(string, "B1") == 0) 
{
  // do something
} 
else if (strcmp(string, "xxx") == 0)
{
  // do something else
}
/* more else if clauses */
else /* default: */
{
}

1
Trên thực tế, vấn đề là tôi đã có một công tắc trên int và trong một trường hợp đặc biệt, tôi có giá trị "B1" và "B2" mà tôi muốn sử dụng trong cùng một công tắc. Cách duy nhất là bằng cách nào đó chuyển đổi các giá trị "B1" và "B2" và sử dụng chúng dưới dạng int !!?
Niklas

2
@Niklas: Đây là thông tin quan trọng cho câu hỏi của bạn. Bạn có thể cập nhật câu hỏi của mình và giải thích (nếu có thể bằng một số mã (giả)) những gì bạn đang cố gắng làm không?
Bart van Ingen Schenau

4
@Niklas: Bạn nên làm rõ câu hỏi của mình: làm thế quái nào mà "B1" và "B2" lại là một trường hợp đặc biệt của một int?
Edgar Bonet

1
#define A 1 #define B 2 #define C S1 #define D S2 và những giá trị này là những gì tôi muốn sử dụng trong công tắc của mình. Thật đơn giản :-)
Niklas

5
@Niklas: Định nghĩa không phải là chuỗi. Nếu định nghĩa dành cho một số, bạn có thể sử dụng nó trực tiếp trong công tắc của mình như thế này switch (something) { case A: /*...*/ break; case B: /*...*/ break; }.
Bart van Ingen Schenau,

45

Nếu bạn gặp nhiều trường hợp và không muốn viết nhiều strcmp()cuộc gọi, bạn có thể làm như sau:

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

Bạn chỉ cần đảm bảo rằng hàm băm của bạn không có xung đột bên trong tập hợp các giá trị có thể có cho chuỗi.


8
"hãy đảm bảo rằng hàm băm của bạn không có xung đột bên trong tập hợp các giá trị có thể có cho chuỗi." - Có tồn tại một hàm băm như vậy cho bảng chữ cái [a-zA-Z0-9_]không? Có ví dụ nào không?
Arun

8
@ArunSaha: Rõ ràng là không dành cho sự kết hợp tùy ý của các ký tự như vậy.
Edgar Bonet

3
Nếu bạn sử dụng các khóa chuỗi có độ dài cố định, bạn có thể chuyển đổi chúng thành các số nguyên duy nhất; không có va chạm có thể.
Engineer

@ArcaneEngineer Ừm ... đó không phải là vấn đề chính xác mà câu hỏi đang cố gắng giải quyết sao? Làm thế nào, chỉ với chuỗi, bạn sẽ chọn ra một số nguyên để đi cùng với nó? "sử dụng một công tắc hoặc if / else bậc thang" Hoặc có thể bạn có nghĩa là một cái gì đó rất ngắn như 4 ký tự?
ebyrob

@ebyrob Ý tôi là bất cứ thứ gì có thể so sánh được trong một thao tác nhanh, chẳng hạn như 2 bit 64 bit uintcó bit được coi là 8 ASCII 1 byte char. Tôi đã triển khai điều này một thời gian trước, để so sánh chính trong bảng băm trong C. Do đó, bạn loại bỏ nhu cầu về bất kỳ băm hoặc nhóm nào. Vấn đề nằm ở chỗ bạn cần vượt quá 64 bit; sau đó bạn phải trả chi phí cho các điều kiện khi bạn lặp lại từng bộ 8 chars trong chuỗi đầy đủ. Trừ khi bạn mở vòng lặp, nếu bạn biết kích thước tối đa của các phím. Đó là một hành động cân bằng tốt.
Kỹ sư

39

Không có cách nào để làm điều này ở C. Có rất nhiều cách tiếp cận khác nhau. Thông thường, cách đơn giản nhất là xác định một tập hợp các hằng số đại diện cho các chuỗi của bạn và thực hiện tra cứu theo từng chuỗi để nhận được hằng số:

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

Tất nhiên, có nhiều cách hiệu quả hơn để làm điều này. Nếu bạn sắp xếp các khóa của mình, bạn có thể sử dụng tìm kiếm nhị phân. Bạn cũng có thể sử dụng bảng băm. Những điều này thay đổi hiệu suất của bạn với chi phí bảo trì.


7
Tốt hơn nhiều khi sử dụng một enum thay vì một tập hợp các #defines cho các phím, nhưng nếu không thì đó là điều tốt nhất bạn có thể làm.
Craig Ringer

tăng không chính xác. lookuptable + i * sizeof (t_symstruct) không bằng lookuptable [i].
asdf

@asdf Đó là cách hoạt động của số học con trỏ trong c. Kích thước là ngầm định.
ijustlovemath

20

Phương pháp ưa thích của tôi để làm điều này là thông qua một hàm băm (mượn từ đây ). Điều này cho phép bạn sử dụng hiệu quả của câu lệnh switch ngay cả khi làm việc với 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);
    }
}

Tất nhiên, cách tiếp cận này yêu cầu các giá trị băm cho tất cả các char * được chấp nhận có thể được tính toán trước. Tôi không nghĩ rằng đây là một vấn đề quá lớn; tuy nhiên, vì câu lệnh switch hoạt động trên các giá trị cố định bất kể. Một chương trình đơn giản có thể được thực hiện để chuyển char * qua hàm băm và xuất ra kết quả của chúng. Các kết quả này sau đó có thể được xác định thông qua macro như tôi đã làm ở trên.


Chào mừng bạn đến với Stack Overflow. Những gì bạn đã trình bày được trình bày độc đáo và là một ý tưởng hay, nhưng… nhưng tất cả không phải là điều khác biệt rõ ràng so với một số câu trả lời khác - có một số câu trả lời sử dụng các biến thể nhỏ cho ý tưởng này. Nếu bạn thêm câu trả lời mới cho một câu hỏi ổn định cũ, bạn nên chắc chắn rằng bạn có thông tin mới tốt. Đó chủ yếu là một lời cảnh báo; Tôi chắc chắn sẽ không bỏ phiếu cho bạn vì điều này.
Jonathan Leffler

16

Tôi nghĩ cách tốt nhất để làm điều này là tách biệt 'công nhận' khỏi chức năng:

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

}

8

Tôi đã xuất bản tệp tiêu đề để thực hiện chuyển đổi trên các chuỗi trong C. Nó chứa một tập hợp macro ẩn lệnh gọi đến strcmp () (hoặc tương tự) để bắt chước hành vi giống như chuyển đổi. Tôi đã thử nghiệm nó chỉ với GCC trong Linux, nhưng tôi khá chắc chắn rằng nó có thể được điều chỉnh để hỗ trợ môi trường khác.

CHỈNH SỬA: đã thêm mã ở đây, theo yêu cầu

Đây là tệp tiêu đề bạn nên bao gồm:

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

Và đây là cách bạn sử dụng nó:

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;

Tôi đã chỉnh sửa ví dụ này không phải bằng cách thêm "dấu ngắt", mà nêu bật thực tế là bạn có thể bỏ qua nó
Andrea Carron

1
đó là tốt hơn! Trước khi tôi sử dụng "sscanf" để đối sánh, tôi đã học "regex.h", điều này rất hữu ích với các trường hợp chuỗi :)
LinconFive

Thật là một giải pháp đẹp, dễ đọc và nhiều chức năng hơn so với một công tắc / thùng máy - Cảm ơn! Đừng quên "switchs_end:" sau khi đóng dấu ngoặc.
Achim

6

Có một cách để thực hiện tìm kiếm chuỗi nhanh hơn. Giả định: vì chúng ta đang nói về câu lệnh switch, tôi có thể giả định rằng các giá trị sẽ không thay đổi trong thời gian chạy.

Ý tưởng là sử dụng qsort và bsearch của C stdlib.

Tôi sẽ làm việc trên mã của 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;
}

6

Để thêm vào câu trả lời của Phimueme ở trên, nếu chuỗi của bạn luôn là hai ký tự, thì bạn có thể xây dựng một số int 16 bit trong số hai ký tự 8 bit - và bật điều đó (để tránh các câu lệnh switch / case lồng nhau).


Nếu bạn thực sự muốn To add to Phimueme's answer above, hãy sử dụng chức năng bình luận. :)
Onion-Knight

3
@Onion: Bạn sẽ lưu ý rằng MikeBrom hiện không có danh tiếng để nhận xét về các bài đăng không phải của anh ấy và câu trả lời cho các câu hỏi của chính anh ấy. Điều đó nói rằng, @Mike "ở trên" là trơn trong SO, vì không có thứ tự sắp xếp đáng tin cậy. Tốt hơn nên liên kết đến câu trả lời như "... trong câu trả lời của Phimueme ..." (mặc dù câu trả lời đó hiện đã bị xóa và liên kết chỉ tốt cho người dùng có 10k + danh tiếng).
dmckee --- ex-moderator kitten

3

Chúng ta không thể thoát if-else bậc thang để so sánh một chuỗi với những chuỗi khác. Ngay cả switch-case thông thường cũng là một thang if-else (đối với số nguyên) trong nội bộ. Chúng tôi có thể chỉ muốn mô phỏng trường hợp chuyển đổi cho chuỗi, nhưng không bao giờ có thể thay thế thang if-else. Các thuật toán tốt nhất để so sánh chuỗi không thể thoát khỏi việc sử dụng hàm strcmp. Có nghĩa là so sánh từng ký tự cho đến khi tìm thấy kết quả không khớp. Vì vậy việc sử dụng if-else Ladder và strcmp là không thể tránh khỏi.

BẢN GIỚI THIỆU

Và đây là các macro đơn giản nhất để mô phỏng trường hợp chuyển mạch cho chuỗi.

#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

Và bạn có thể sử dụng chúng như

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

Đầu ra:

in def
in ghi
in DEFAULT

Dưới đây là cách sử dụng SWITCH lồng nhau:

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

Đầu ra:

in def
in def => xyz
in ghi
in DEFAULT

Đây là SWITCH chuỗi ngược, trong đó bạn có thể sử dụng một biến (thay vì một hằng số) trong mệnh đề CASE:

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

Đầu ra:

in str3

"Ngay cả switch-case thông thường cũng là một thang if-else (đối với số nguyên) bên trong" điều đó không đúng. Nếu có thể, trình biên dịch sẽ tạo bảng nhảy, bảng này sẽ hiệu quả hơn nhiều. Xem stackoverflow.com/a/14067661/4990392
Dada

2

Đây thường là cách tôi làm.

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

Hấp dẫn. Thiếu (có thể do lựa chọn) mã hóa phòng thủ. Và tôi ngưỡng mộ các niềng răng bổ sung trong trường hợp. Làm cho mã dễ đọc hơn nhiều (mặc dù tôi thích dấu ngoặc nhọn người Ai Cập hơn cho trường hợp).
Dariusz

1
BTW, bạn có thể sử dụng các biểu thức hằng trong các nhãn trường hợp. case 'B'<<8+'1':Tôi nghĩ sẽ làm cho điều này rõ ràng hơn 0x4231.
Jens

Tôi sẽ sử dụng một macro. #define twochar(a) (((uint16_t)a[1]<<8)|a[0])
v7d8dpo4

1

Đây là cách bạn làm điều đó. Không thật sự lắm.

#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
Tôi không nghĩ đây là tiêu chuẩn C.
Johan Kotlinski

2
Làm cho macro hỗ trợ kết thúc hỗn hợp hoặc một chức năng được để lại như một bài tập cho người đọc.

2
Nó là tiêu chuẩn C, nhưng không phải là di động. Thứ tự byte của char nhiều byte là 'phụ thuộc thực thi' và không cần phản ánh thứ tự byte của máy. Tôi sử dụng một lần và đã bị cháy: trên Solaris SPARC (về cuối lớn) GNU-C 3.4 sử dụng một thứ tự byte khác với Sunstudio 12.
Patrick Schlüter

@tristopia Tất nhiên là bạn đã đúng (đúng như người ta có thể làm được sau khi cố gắng làm điều gì đó như thế này là thật). Đây là lý do tại sao tất cả chúng ta nên sử dụng B để thay thế.

Tại sao bạn giết tài khoản của mình?

1

Nếu đó là một chuỗi 2 byte, bạn có thể làm điều gì đó như trong ví dụ cụ thể này, nơi tôi bật mã ngôn ngữ 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_ * là số nguyên không đổi được sử dụng để lập chỉ mục trong mảng.


0

Giả sử ít endianness và sizeof (char) == 1, bạn có thể làm điều đó (điều gì đó như thế này do MikeBrom đề xuất).

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

Nó có thể được tổng quát cho trường hợp BE.


2
Đừng làm vậy! Điều này có thể gây ra ngoại lệ "căn chỉnh dữ liệu". Nó không được đảm bảo rằng char * txt trỏ đến một địa chỉ phù hợp với yêu cầu căn chỉnh của int.
harper

@R anh ấy đã yêu cầu điều đó. @harper không phải là trường hợp của x86.
ruslik

Niklas không yêu cầu x86. Và vì bạn đã đề cập đến trường hợp endian lớn, bạn không giải quyết riêng môi trường x86. Vì vậy, điều đó '
harper

Hơn nữa, các ký tự nhiều byte không nhất thiết phải theo thứ tự byte máy. Xem bình luận của tôi để jbcreix trả lời.
Patrick Schlüter

0

Con trỏ hàm là một cách tuyệt vời để làm điều này, ví dụ:

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

... điều này gọi một hàm mà bạn đã đặt bằng phím chuỗi (một hàm cho mỗi trường hợp):

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

Sử dụng triển khai hashmap / table / từ điển có sẵn từ trước chẳng hạn như khash, trả lại con trỏ đó cho một hàm bên trong switchFunction()và thực thi nó (hoặc chỉ cần trả lại từ đó switchFunction()và tự thực thi nó). Nếu việc triển khai bản đồ không lưu trữ điều đó, chỉ cần sử dụng một uint64_tthay thế mà bạn truyền cho một con trỏ.


@ eri0o Nếu bạn nghĩ nó là tốt, tại sao không ủng hộ nó? Chiếc downvoter nguyên bản đã mất từ ​​lâu.
Engineer

-2

Xin chào, đây là cách dễ dàng và nhanh chóng nếu bạn gặp trường hợp này:

[Chế độ NHANH]

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

[Chế độ GIẢI THÍCH]

ví dụ: tôi có nhiều menu, mỗi lựa chọn trên menu thứ nhất sẽ đưa bạn đến menu thứ 2, điều tương tự với menu thứ 2 và menu thứ 3. nhưng các Options khác nhau để bạn biết rằng người dùng đã chọn phần phân tích. ví dụ:

menu 1: 1 ==> menu 2: 4 ==> menu 3: 2 (...) lựa chọn là 142. trường hợp khác: 111,141,131,122 ...

sollution: lưu trữ thứ nhất đầu tiên trong a, thứ 2 trong b, thứ 3 trên 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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.