c89中的指示符

时间:2016-07-23 21:20:07

标签: c enums c89 string-table

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的要求工作。

我已经研究过预处理器魔术(例如在here中),但我需要字符串是任意的,而不是枚举符号的副本。

仅仅做

是不够的
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 个答案:

答案 0 :(得分: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");

符号和字符串是成对的。您不容易在没有字符串的情况下添加新符号,反之亦然。要添加元素,您必须为宏添加两个新参数 - E3, S3 - 依此类推。没有任何内容可以保持同步,只是enum包含所有E - s且数组中包含所有S - s。这几乎是不可能搞砸的。

答案 1 :(得分:1)

简单,老式的

const char* table[] = { "foo", "bar", "baz" };

换句话说,只需按正确顺序排列。

char *foo_string = table[FOO];

当然,这仅适用于上述简单的枚举,而不适用于风格中的枚举

enum { FOO = 13; BAR = 15, BAZ = 312 };

但是为此,你必须创建一个至少包含313个元素的数组,其中大部分都是NULL,这将是一个非常浪费的构造。在这种情况下,当您使用switch构造时,编译器可以为您优化。

另请参阅S.O.问题@Leandros指出:How to convert enum names to string in c。答案是使用宏来生成数组,这可以确保条目的顺序正确。

或者,正如答案所说:

#define enum_str(s) #s

完全摆脱阵列。

答案 2 :(得分:1)

您可以使用X-Macros将它们保持在一起:

actionProgram()

现在您的新数据可以添加为一组枚举和字符串。如果您以后决定根据枚举添加其他内容,则可以使用' z' OP()或甚至#define MYXMACRO(OP) \ OP(ENUM_FOO, "foo") \ OP(ENUM_BAR, " bar") \ OP(ENUM_BAZ, "baz") /* use the first parameter to set up your enums*/ enum { #define AS_ENUMS(x,y) x, MYXMACRO(AS_ENUMS) #undef AS_ENUMS /*not required, just playing nice*/ NUMTHINGS }; /* use the 2nd parameter to set up your strings*/ const char *strings[] = { #define AS_STRINGS(x,y) y, MYXMACRO(AS_STRINGS) #undef AS_STRINGS }; #undef MYXMACRO ...的参数,用于多个但数量不同的参数。

答案 3 :(得分: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"
}

它有点难看(有点可爱,你知道吗?)但是效果很好。