3

在调整某些给定接口时,我遇到了扩展头文件使用的问题,其中包含大量#defines.

我所拥有的是这样的:

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

有很多这样的定义,我很高兴,因为我不必把它们都写出来。

但是,虽然我可以很好地将它们用于switch,if和其他语句作为等的替代品0x00,但我现在想要相反的方向。

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

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

arrayNames[STATUS_OK] = _STATUS_OK_

STATUS_OK将在哪里解决0x00并将解决到“ STATUS_OK _STATUS_OK_”?

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

这将是我希望能够做到的:

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

我希望,我明确了我在寻找什么。

编辑:

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

4

6 回答 6

3

您可以使用一点宏魔法和预处理器的字符串化操作符来完成它。看一看:

#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 常量的名称。

这是ideone与此工作示例的链接。

于 2012-11-22T17:36:44.833 回答
2

使用X-Macros,尽管它需要更改您的原始头文件

于 2012-11-22T17:00:18.270 回答
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"
于 2012-11-22T17:30:48.050 回答
1

你可以这样做:

const char *status_str(int s)
{
    switch(s)
    {
        case STATUS_OK:
            return "STATUS_OK";
        /* And so on and so forth */
    }
}
于 2012-11-22T16:59:25.497 回答
1

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

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

于 2012-11-22T16:59:44.010 回答
1

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

identifier value

例如

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在标识符表更改时生成模块和标题。

于 2012-11-22T17:00:12.703 回答