2016-07-27 5 views
5

次のように書き直すことはできますか?文字列が変更された場合、変更する必要があるのは1か所だけです。定数文字列の最初の文字を定数文字として自動的に取得する方法はありますか?

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

目的が効率的です1文字を見て受信した文字列を解析します。私の場合、すべての文字列には一意の文字が1つあります。以下は、原理を示すために、私の実際のコードが、非常に単純な例ではありません。

#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のドキュメントでこれを見つけた: 「文字にマクロ引数を変換する方法はありません定数。"

定義は、いくつかのソースファイルで共有できるインクルードファイルに入れたかったのです。これは私が得ることができる限り近くにあり、すべての文字は1か所にしか定義されていません。

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

私はそうしません。元の質問は、1つの定義を共有して文字列定数と文字定数の両方を取得できるかどうかでした。実行時にクロックサイクルを無駄にすることで、私の問題に対するいくつかの解決策があります。

+3

興味深い質問にあなたのスイッチ/ケースから処理コードを移動する必要があります。私はそれが可能であるとは思わない。しかし、私にはXY問題のようなにおいがします。 –

+1

ケースラベルの文字を使用する場合は、[整数定数式](http://port70.net/~nsz/c/c99/n1256.html#6.6)が必要です。 – nwellnhof

+0

[switch case:error:大文字小文字のラベルが整数定数に還元されない可能性があります](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

私は似たような、しかし醜い例を元の投稿に追加した後、これを見ました。あなたのソリューションはよりエレガントです。 – 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

このコードは、O(1)時間で動作する 'switch'ベースのアプローチと比較して、求められる効率が欠けています。そのコードのパフォーマンスがそれほど重要であるかどうかは、OPだけが知ることができます。 – Leon

+0

@リオン私はあなたの声明に同意しない。パフォーマンスの観点から、コンパイラの最適化を考慮する必要があります。上記のコードでは、パフォーマンスの最適化用に構成された現代のコンパイラは、結果として得られるバイナリコードを単純なスイッチ/ケースとほぼ同じにするループアンロールを実行します。コンパイラがあなたよりも優れた処理能力を発揮できるように、コードの可読性を犠牲にして初期の最適化を行うことは、しばしば悪い考えです。 – greydet

+0

ループアンロールでは、テーブルを介して一定時間の検索を実行できません。読みやすさとパフォーマンスはどうなるのですか?私はあなたと同意します。私の最初のコメントにはその兆候が含まれています。 – Leon

関連する問題