1

C99 では、配列初期化子 (とりわけ) が、配列のどの要素を正の整数指定子 ($6.7.8.6、$6.7.8.17) で設定するかを指定できます。たとえば、次のようになります。

const char *foo[] = {[2] = "foo", [1] = "bar", [0] = "baz"};

私は以前にこれを使用して、列挙型から文字列へのテーブルを次のように作成しました。

enum {THING_FOO = 0, THING_BAR, THING_BAZ};
const char *table[] = {
    [THING_FOO] = "foo",
    [THING_BAR] = "bar",
    [THING_BAZ] = "baz"
}

ただし、現在、コードが c89 に準拠しているという要件の下で作業しています。

私はプリプロセッサの魔法を調べました (たとえば、ここのように) が、列挙型シンボルのコピーではなく、文字列を任意にする必要があります。

するだけでは不十分

enum {THING_FOO = 0, THING_BAR, THING_BAZ};
const char *table[] = {"foo", "bar", "baz"};

将来、列挙要素を追加する必要があるためです。c99 メソッドを使用すると、テーブルに NULL ポインターが発生し、問題が発生した場合にデバッグが容易になります。このメソッドを使用して文字列テーブルを更新するのを忘れると、デバッグが困難なセグメンテーション違反が発生します。また、とにかくオフセットを覚えておく必要がある場合、シンボルを持つという点が無効になります。

宣言が関数内にある場合、次のように目的の効果を達成できます。

enum {THING_FOO = 0, THING_BAR, THING_BAZ, NUM_THINGS};
void foo(void)
{
    static const char *table[NUM_THINGS];
    table[THING_FOO] = "foo";
    table[THING_BAR] = "bar";
    table[THING_BAZ] = "baz";

    /* ... */
}

ただし、少なくとも ではgcc、これは最適化されません。

c89 でそのような文字列テーブルを宣言する方法はありますか? (組み立てには問題ありません。)

4

4 に答える 4

2
 #define DEF_FOO_ENUM(E0, S0, E1, S1, E2, S2) \
   enum foo                { E0, E1, E2 };    \
   const char *foo_str   = { S0, S1, S2 };

 DEF_FOO_ENUM(THING_FOO, "foo",
              THING_BAR, "bar",
              THING_BAZ, "baz");

記号と文字列はペアになっています。文字列なしで新しいシンボルを簡単に追加することはできません。逆もまた同様です。要素を追加するには、マクロに 2 つの新しい引数が必要ですE3, S3— — など。そこには同期を維持するものは何もありません。ただ、 にenumはすべてE-s があり、配列にはすべてS-s があります。これを台無しにすることはほとんど不可能です。

于 2016-07-23T23:27:21.353 に答える
0

いくつかの異なる手法を試した後、これが維持するのが最も簡単です。

const char *table[] = {
#define FOO 0
    "foo",
#define BAR (FOO + 1)
    "bar",
#define BAZ (BAR + 1)
    "baz"
}

ここでは、エントリに関するすべての情報がクラスター化されています。要素を挿入するには、その周りのものを変更するだけです。たとえば、挿入するにはqux

const char *table[] = {
#define FOO 0
    "foo",
#define QUX (FOO + 1)    /* new */
    "qux",               /* new */
#define BAR (QUX + 1)    /* modified */
    "bar",
#define BAZ (BAR + 1)
    "baz"
}

少し醜いですが(ちょっとかわいらしいですね)、うまく機能します。

于 2016-08-24T03:30:57.723 に答える