【问题标题】:c pre processor string concatenatec预处理器字符串连接
【发布时间】:2012-11-22 05:13:26
【问题描述】:

如何组合预定义的 C 值来生成字符串。

#define APP_NUMBER 22
#define ICON_FILE  "../icons/"##APP_NUMBER##".ico"

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

 1000 ICON  ICON_FILE

而不是 1000 个图标“../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 语言吗?
  • 我不认为这是一个关于 C 的问题。也许如果你重新标记这个问题,你会得到更好的答案。
  • .rc 文件到底是什么?我猜这是某种资源文件,但是什么样的呢?你用的是什么环境?

标签: c c-preprocessor


【解决方案1】:

这行得通:

#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 文件,这解释了“无法打开图标文件”您收到的消息。

您似乎正在尝试使用标记粘贴来生成字符串文字。问题在于,包含不匹配的" 字符的 partial 字符串文字不能是有效的预处理标记。例如,您不能将单个 " 作为参数传递给宏。

考虑编写一个程序(脚本等),为您生成适当的#define 指令。

【讨论】:

  • 看起来确实如此(资源编译器未连接的字符串文字),不幸的是:stackoverflow.com/a/11161985/163956
  • 好的,但目前我有 1000 个图标“../icons/59.ico”资源编号 1000 是这个图标,但我想做1000 ICON ICON_FILE
  • @AshodApakian:“资源文件”不是 C 语言的特性。如果您需要他们的帮助,您需要告诉我们您使用的是什么环境。请参阅我对这个问题的评论。
【解决方案2】:

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 进行字符串化时存在问题(至少在 Windows 上)。所以 BOOST_PP_STRINGIZE(BOOST_PP_CAT(../icons/, BOOST_PP_CAT(num,.ico))) 不起作用。

3 项连接的加法

#    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

在我的测试 VS2013 中输入

  • .. 正在转换为 "...",这使得使用相对路径 difficult
  • \ 需要转义 \\ 才能在宏 args 中工作,但正在转换为 "\\" - 使用 / 路径效果更好

使用字符串表比使用图标更容易查看输出

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))

【讨论】:

    【解决方案3】:

    老实说,我会避免使用预处理器执行此操作。调试预处理器错误是一件痛苦的事,我见过使用多层预处理器替换和连接的情况,在尝试查找问题时导致灾难。只是我的 2 美分。

    【讨论】:

      【解决方案4】:

      我认为您无法使用 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”以获取更多信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-22
        • 2017-04-02
        • 1970-01-01
        相关资源
        最近更新 更多