有一个值的#define替换列表,如何将值解析为标识符的字符串?

时间:2012-11-22 16:53:40

标签: c c-preprocessor

在调整某些给定界面时,我遇到了扩展使用带有大量#defines的头文件的问题。

我所拥有的是这样的:

#define STATUS_OK      0x00
#define STATUS_FAIL    0x01
#define STATUS_WAIT    0x02
#define STATUS_ILLEGAL 0x03
#define STATUS_FULL    0x04
...

有很多像这样的定义,我很高兴,因为我不必全部写出来。

但是,虽然我可以很好地将它们用于switchif以及其他语句作为0x00等的替代,但我现在希望有反对方向。< / p>

所以,有了0x00,我想打印出标识符“STATUS_OK”。

据我所知,这是不可能的,但是什么是一个很好的解决方法,使它成为可能?!是否可以设置这样的数组:

arrayNames[STATUS_OK] = _STATUS_OK_

STATUS_OK解析为0x00_STATUS_OK_将解析为“STATUS_OK”?

此外,我正在寻找一种尽可能少使用内存的解决方案。

这是我希望能够做到的:

prinf("%s",resolve(0x00));
-> "STATUS_OK"

我希望,我明确了我要找的东西。

编辑:

感谢所有人,快速而有用的回复!我将使用Larsmans解决方案,并可能尝试将其与qrdl结合使用。可能需要一段时间,我会在完成后替换此编辑。

6 个答案:

答案 0 :(得分:3)

您可以使用预处理器的小宏模板和 stringize 运算符来执行此操作。看看:

#include <stdio.h>
#define STATUS_OK 0x05
#define STATUS_BAD 0x09
#define LOOKUP_CASE(x) case x: return #x

const char *lookup_name(int val) {
    switch(val) {
        LOOKUP_CASE(STATUS_OK);
        LOOKUP_CASE(STATUS_BAD);
        default: return "<UNDEFINED>";
    }
    return NULL;
}

int main(void) {
    printf("%s\n", lookup_name(STATUS_OK));
    printf("%s\n", lookup_name(STATUS_BAD));
    return 0;
}

LOOKUP_CASE宏外,该示例不言自明。它使用#运算符生成与其操作数对应的字符串常量,从而避免重复#define - d常量的名称两次。

这是一个link to ideone这个有效的例子。

答案 1 :(得分:2)

使用X-Macros,但需要更改原始标头文件

答案 2 :(得分:1)

您可以这样做:

const char *status_str(int s)
{
    switch(s)
    {
        case STATUS_OK:
            return "STATUS_OK";
        /* And so on and so forth */
    }
}

答案 3 :(得分:1)

无法从其值中获取标识符的名称。因为在预处理之后标识符不再可用,并且编译器不知道它们。

但是,您可以尝试将其名称存储在数组或类似的其他技巧中。

答案 4 :(得分:1)

一个简单的解决方案是编写两个非常简单的代码生成器。如果将标识符存储在文本文件中,格式为

identifier value

e.g。

STATUS_OK      0x00
STATUS_FAIL    0x01

然后两个简单的Awk脚本可以生成带有#defines的标头和带有该字符串的C模块。对于标题:

BEGIN {
   print("#ifndef _STATUSCODES_H");
   print("#define _STATUSCODES_H");
}

{ printf("#define %s %s\n", $1, $2) }

END { print("#endif"); }

对于回到字符串的映射:

BEGIN {
    print("#include \"statuscodes.h\"");
    print("char const *status_string(int status)");
    print("{");
    print("    switch (status) {");
}

{ printf("      case %s: \"%s\"\n", $2, $1); }

END {
    print("    }");
    print("}");
}

然后,当标识符表更改时,让Makefile生成模块和标题。

答案 5 :(得分:1)

如果没有使用switch检查每个值或制作包含名称的完整列表,我认为没有针对您的问题的解决方案:

char *s_names[] = {
    "STATUS_OK",
    "STATUS_FAIL",
    ...
}

现在您可以通过索引(这是错误代码)简单地访问字符串:

printf("%s", s_names[0x00]);      // prints "STATUS_OK"
printf("%s", s_names[STATUS_OK]); // prints "STATUS_OK" too

如果您有值(或宏),这将有效但如果您不想为整个列表浪费太多空间,则可以使用此宏:

#define MACRO_TO_STRING(x) #x

现在您可以将宏转换为字符串,但不能将值转换为字符串:

printf("%s", MACRO_TO_STRING(STATUS_OK)); // prints "STATUS_OK"
printf("%s", MACRO_TO_STRING(0x00));      // but this doesn't work: prints "0x00"