2016-07-27 17 views
5

是否可以重寫以下內容,因此如果字符串更改,只需在一個位置更改?如何自動獲取常量字符的第一個字符作爲常量字符?

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

以下是不能接受的,因爲它是指在一個存儲器位置的炭,因此它不能用作在switch語句的情況下:

#define MY_STRING_FIRST_CHAR MY_STRING[0] 

switch (something) { 
    case MY_STRING_FIRST_CHAR: 
     break; 
} 

的目的是有效地通過查看一個字符來解析收到的字符串。在我的情況下,所有字符串都有一個唯一的字符以下是不是我的實際代碼,而是一個很簡單的例子來說明這樣的原則:

#define COMMAND_LIST    "list" 
#define COMMAND_LIST_FIRST_CHAR 'l' 
#define COMMAND_CHANGE   "change" 
#define COMMAND_CHANGE_FIRST_CHAR 'c' 
#define COMMAND_EXIT    "exit" 
#define COMMAND_EXIT_FIRST_CHAR 'e' 

switch(received_command_string[0]){ 
    case COMMAND_LIST_FIRST_CHAR: 
    // Do the "list" stuff 
    break; 
    case COMMAND_CHANGE_FIRST_CHAR: 
    // Do the "change" stuff 
    break; 
    case COMMAND_EXIT_FIRST_CHAR: 
    // Do the "exit" stuff 
    break; 
} 

用戶「PMG」發現這個gcc的文檔中: 「有沒有辦法一個宏參數轉換爲一個字符不變。」

我希望定義在一個包含文件中,它可以被幾個源文件共享。這是儘可能接近,而只有每個字符定義在一個地方:

#include <stdio.h> 
#define CH0 'F' 
#define CH1 'o' 
#define CH2 'o' 
#define CH3 ' ' 
#define CH4 'b' 
#define CH5 'a' 
#define CH6 'r' 
static char MY_STRING[] = { CH0, CH1, CH2, CH3, CH4, CH5, CH6, '\0'}; 
#define MY_STRING_FIRST_CHAR CH0 

void main(void){ 
    printf("The string is %s, the first char is %c\n", MY_STRING, MY_STRING_FIRST_CHAR); 
} 

我不會這樣做。最初的問題是如果可以共享一個定義來同時獲得字符串常量和字符常量。通過在運行時間浪費時鐘週期,我的問題有幾種解決方案。

+3

有趣的問題。我懷疑這是可能的。但是聞起來像XY-問題。 –

+1

如果你想使用case標籤中的字符,你需要一個[整型常量表達式](http://port70.net/~nsz/c/c99/n1256.html#6.6)。 – nwellnhof

+0

[switch case:error:case label does not reduce to a integer constant]可能的重複(http://stackoverflow.com/questions/14069737/switch-case-error-case-label-does-not-reduce-to -an-integer-constant) – jweyrich

回答

-4
#define MY_STRING "Hello" 

const char var[] = MY_STRING; 

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

這應該解決它。

+3

它可以用在switch語句中嗎?人們在回答之前閱讀這個問題! –

+1

請仔細閱讀(更新)的問題 – Leon

3

你可以做到這一點與一次寫入每個符號......但不同的定義

#include <stdio.h> 

#define COMMAND_LIST_FIRST_CHAR 'l' 
#define COMMAND_LIST    (char[]){ COMMAND_LIST_FIRST_CHAR, 'i', 's', 't', 0 } 

int main(void) { 
    char received_command_string[] = "list"; 
    switch (received_command_string[0]) { 
     case COMMAND_LIST_FIRST_CHAR: 
      printf("Doing the \"list\" stuff for '%s'\n", COMMAND_LIST); 
      break; 
     default: 
      break; 
    } 
    return 0; 
} 
+0

Oooops,我在原始帖子中添加了類似但較爲醜陋的示例之後看到了這一點。你的解決方案更加優雅。 – Hans

+2

我的醜陋解決方案沒有明確指定字符串長度,但似乎常量「5」也可以從代碼中刪除。 – Hans

1

爲什麼你絕對要使用開關的情況下?

相反,您可以使用匹配您的字符串和處理函數的映射表。然後你只需遍歷表格。

typedef struct { 
    char * key; 
    void (func*)(void); 
} MAP_ENTRY; 

MAP_ENTRY map [] = { 
    {"list", listHandler}, 
    {"change", changeHandler}, 
    {"exit", exitHandler}, 
}; 

for (i = 0; i < sizeof(map)/sizeof(map[0]); i++) { 
    if (map[i].key[0] == received_command_string[0]) { 
     map[i].func(); 
     break; 
    } 
} 

然後你只需從你的交換機/時的處理代碼移動到相應的處理函數

+1

與基於'switch'的方法相比,這個代碼缺乏效率,這個方法可以在O(1)時間內工作。代碼的性能是否真的非常重要,只有OP可以說明。 – Leon

+0

@Leon我不同意你的發言。從性能角度來看,您必須考慮編譯器優化。通過上面的代碼,爲性能優化配置的任何現代編譯器都會執行循環展開,這將使得生成的二進制代碼幾乎與簡單的開關/事例相同。犧牲代碼可讀性以使編譯器比你更好地做出早期優化通常是一個糟糕的主意。 – greydet

+0

循環展開無法實現通過表進行恆定時間查找。可讀性和性能有什麼關係,我同意你的看法,而我的第一條評論就包含了這一點。 – Leon

相關問題