C预处理器字符串连接

4
我该如何将预定义的C值组合起来生成一个字符串。
#define APP_NUMBER 22
#define ICON_FILE  "../icons/"##APP_NUMBER##".ico"

这样我就可以在我的.rc文件中执行以下操作:

 1000 ICON  ICON_FILE

使用以下代码代替 1000 ICON "../icons/22.ico"

它无效了

  #define MY_ICON_FILE 25
  #define STR(x) #x
  #define ICON_FILE_NUM(x) "../icons/" STR(x) ".ico"
  1000 ICON  ICON_FILE_NUM(MY_ICON_FILE)

编译器错误
  can't open icon file `../icons/': Permission denied

  nothing was appended to "../icons/"

我尝试过的最接近的方法是这样的:

  #define MY_ICON_FILE 25
  #define STR(x) #x
  #define ICON_FILE_NUM(x) "../icons/"STR(x)".ico" /// took out spaces
  1000 ICON  ICON_FILE_NUM(MY_ICON_FILE)

(去掉STR(x)周围的空格)并得到了这个编译器错误。
 can't open icon file `../icons/"25".ico': Invalid argument

这真的是关于资源文件而不是C语言的问题吗? - Dietrich Epp
我认为这不是关于C语言的问题。也许如果您重新标记问题,您会得到更好的答案。 - Dietrich Epp
什么是 .rc 文件呢?我猜它应该是某种资源文件,但具体是哪种呢?你在使用哪种开发环境? - Keith Thompson
4个回答

4

这是有效的:

#define APP_NUMBER 22
#define STR(x) #x
#define ICON_FILE_NAME(num)  "../icons/" STR(num) ".ico"
#define ICON_FILE ICON_FILE_NAME(APP_NUMBER)

#include <stdio.h>
int main(void) {
    printf("ICON_FILE = \"%s\"\n", ICON_FILE);
    return 0;
}

输出结果如下:
ICON_FILE = "../icons/22.ico"

但是ICON_FILE宏会扩展为"../icons/" "22" ".ico",这是C语言的有效语法(相邻的字符串字面量被连接在一起),但可能不适用于.rc文件,这就解释了你得到的“无法打开图标文件”的消息。
看起来你正在尝试使用token-pasting来生成一个字符串字面量。问题在于,只包含一个未匹配的"字符的部分字符串字面量不能成为有效的预处理令牌。例如,你不能将单个"作为宏的参数传递。
考虑编写一个程序(脚本或其他)为你生成适当的#define指令。

看起来确实是这样的(字符串文字没有被资源编译器连接):http://stackoverflow.com/a/11161985/163956。 - Greg Inozemtsev
好的,但是在RC文件(资源)中如何工作呢? 目前我有1000个图标“../icons/59.ico” 资源编号1000是这个图标,但我想做到 1000 ICON ICON_FILE - user967007
@AshodApakian:“资源文件”不是C语言的一个特性。如果你需要帮助,你需要告诉我们你正在使用什么环境。请看我在问题上的评论。 - Keith Thompson

1

Windows资源文件对大多数元素不理解C风格的字符串字面值连接-字符串表可能是唯一的例外。

在使用预处理器宏时的技巧是不要将字符串作为输入起点,预处理器不知道如何去除引号。

仅进行一次连接也会很有帮助-考虑添加搜索路径"-I../icons/"而不是向资源名称添加路径。

从boost中提取了以下内容,示例使用Windows MSVC,其使用了比我在大多数地方看到的更多的间接级别。

#    define BOOST_PP_CAT(a, b) BOOST_PP_CAT_OO((a, b))
#    define BOOST_PP_CAT_OO(par) BOOST_PP_CAT_I ## par
#    define BOOST_PP_CAT_I(a, b) a ## b

#    define BOOST_PP_STRINGIZE(text) BOOST_PP_STRINGIZE_A((text))
#    define BOOST_PP_STRINGIZE_A(arg) BOOST_PP_STRINGIZE_I arg
#    define BOOST_PP_STRINGIZE_I(text) #text

在示例中,你只需要执行BOOST_PP_CAT(../icons/, BOOST_PP_CAT(num,.ico))
存在一个问题,仅对外部CAT应用stringize(至少在Windows上)。所以BOOST_PP_STRINGIZE(BOOST_PP_CAT(../icons/, BOOST_PP_CAT(num,.ico)))不起作用。
添加三个项目的连接。
#    define BOOST_PP_CAT2(a, b, c) BOOST_PP_CAT_OO2((a, b, c))
#    define BOOST_PP_CAT_OO2(par) BOOST_PP_CAT_I2 ## par
#    define BOOST_PP_CAT_I2(a, b, c) a ## b ## c

在我的测试中,输入

  • ..被转换为"...",这使得使用相对路径困难
  • \需要转义\\才能在宏参数中工作,但被转换为"\\"——使用/更适合路径

与字符串表进行操作可以比使用图标更容易看到输出

STRINGTABLE
BEGIN
  123  BOOST_PP_STRINGIZE(BOOST_PP_CAT(APP_NUMBER, .ico))
  124  BOOST_PP_STRINGIZE(BOOST_PP_CAT2(../icons/, APP_NUMBER,.ico)))
END

我还没有解决...被转换为...的分辨率问题。 我使用了以下附加搜索路径进行工作。
1000        ICON        BOOST_PP_STRINGIZE(BOOST_PP_CAT(APP_NUMBER, .ico))
1001        ICON        BOOST_PP_STRINGIZE(BOOST_PP_CAT2(icons/, APP_NUMBER, .ico))

-1
我个人会避免使用预处理器来完成这个任务。调试预处理器错误非常麻烦,我曾经见过一些情况,其中使用了多层预处理器替换和连接,导致在查找问题时出现灾难性的后果。这只是我的个人意见。

-1

我认为你无法使用C预处理器完成这个任务。但是,你可以使用m4预处理器来完成。

linux_prompt> cat icon.m4
define(APP_NUMBER, 22)

1000 ICON "../icons/APP_NUMBER.ico"

linux_prompt> m4 icon.m4

1000 ICON "../icons/22.icon"

你必须确保文件的其余部分正确扩展。请参阅'man m4'以获取更多信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接