【问题标题】:Attempt to use preprocessor macros to generate include paths尝试使用预处理器宏生成包含路径
【发布时间】:2015-11-27 07:51:59
【问题描述】:

所以我认为我想要做的事情在 GCC 中是不可能的,因为宏扩展必须导致预处理器令牌。这在 MSVC++ 中运行良好,但我找不到可比的

所以我认为这在 GCC 中是不可能的(在 VC++ 中可以正常工作),因为宏扩展必须是预处理器标记并且被认为是标记之间的分隔符。

我正在尝试链接特定版本的库,在本例中是 Lua 5.3.1。我将文件提取到我的源文件夹中,以便可以在子文件夹“lua-5.3.1\src”中找到它们,我想编写一个宏,我可以使用该宏在头文件中添加该路径的前缀。像LUA_PATH(_file) 这样简单的东西会扩展成"lua-5.3.1/src/_file"。通常我只会使用编译器标志来提供一个不同的子文件夹来搜索,但由于我正在处理的项目是如何设置的,这正是我不能做的,也是我试图找到另一种方法的必须在所有地方维护包含路径。

这是我写的小文件(它不会编译,但我可以通过 cpp 运行它来看看它给了我什么)

#define LUASRC lua-5.3.1/src/
#define STRINGIFY(_s) #_s
#define ADDLUAPATH(_path, _file) STRINGIFY(_path ## _file)
#define EVALUATOR(_path, _file) ADDLUAPATH(_path,_file)
#define LUA_PATH(_file) EVALUATOR(LUASRC,_file)

void main (void)
{
        OUTPUTOFMACROHERE => LUA_PATH(lua.h)
}

这给了我在文件上运行 cpp 的以下输出

$ cpp temp.c
# 1 "temp.c"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "temp.c"
void main (void)
{
temp.c:1:29: error: pasting "/" and "lua" does not give a valid preprocessing token
 #define LUASRC lua-5.3.1/src/
                             ^
temp.c:3:44: note: in definition of macro 'ADDLUAPATH'
 #define ADDLUAPATH(_path, _file) STRINGIFY(_path ## _file)
                                            ^
temp.c:5:25: note: in expansion of macro 'EVALUATOR'
 #define LUA_PATH(_file) EVALUATOR(LUASRC,_file)
                         ^
temp.c:5:35: note: in expansion of macro 'LUASRC'
 #define LUA_PATH(_file) EVALUATOR(LUASRC,_file)
                                   ^
temp.c:9:23: note: in expansion of macro 'LUA_PATH'
  OUTPUTOFMACROHERE => LUA_PATH(lua.h)
                       ^
 OUTPUTOFMACROHERE => "lua-5.3.1/src/lua.h"
}

真正令人沮丧的是,倒数第二行正是我想要得到的输出。只是 GCC 认为到达那里是一个错误。

问题是路径末尾的 / 字符。如果您在 LUASRC 定义的末尾取出 / 并运行它,您将得到 OUTPUTOFMACROHERE =&gt; "lua-5.3.1/srclua.h" 没有任何错误.. 除了路径无效。我找不到将字符放在任何地方以将其放入输出带引号的字符串的地方。我已经尝试像_path ## / ## _file 一样将它自己添加,或者将它移动到像LUA_PATH(/lua.h) 这样传入的值。这只是抱怨与它结合的内容(src 或 lua)作为无效的预处理器令牌。

我尝试使用预处理器的字符串进行连接,但#include "string" "string" 似乎只是尝试将这两个字符串作为单独的路径包含在内。显然,如果不搜索子文件夹,则无法打开文件夹并且无法找到确切的文件。这也是将一半变量(路径或文件)作为字符串添加到另一个扩展和字符串化值的结果。这也是简单地尝试用要扩展的路径为我的文件添加前缀#include LUASRC"lua.h" 的结果(GCC 文档说如果它没有找到

是否有另一种策略让它喜欢我缺少的宏定义中的 /?很想知道。

我正在使用 gcc 版本 4.8.2 (Ubuntu 4.8.2-19ubuntu1)

编辑:实际执行此操作的逻辑但更重要的是不执行此操作的原因在下面标记的答案的链接中提供。然而,为了快速参考所有事物,这就是我的小 temp.c 文件最终的样子

#define LUASRC lua-5.3.1/src/
#define EXPAND(_a)              _a
#define STRINGIFY(_s)           #_s
#define EVALUATOR(_args)        STRINGIFY(_args)
#define LUA_PATH(_file)         EVALUATOR(EXPAND(LUASRC)EXPAND(_file))

void main (void)
{
        OUTPUTOFMACROHERE => LUA_PATH(lua.h)
}

【问题讨论】:

    标签: gcc include concatenation c-preprocessor stringify


    【解决方案1】:

    并不是“gcc 认为这是一个错误”。 一个错误。 (“如果 [串联] 的结果不是有效的预处理标记,则行为未定义。”,C11 §6.10.3.3/3)。

    但这没关系,因为您可以对多个标记进行字符串化;无需连接。您只需要注意空格即可。

    有关示例,请参阅 https://stackoverflow.com/a/32077478/1566221

    【讨论】:

    • 感谢您的回答,我会看一下其他示例。这实际上不是我迄今为止打开的许多 SO 选项卡之一,以帮助寻找它。而且我知道编译器严格遵守它应该做的规范,并通过文档自己的符号清理它曾经允许这样做的内容。在我看来,如果宏扩展的其余部分继续被停止并保留为无效并因此未定义,那么在这种情况下可以定义为有效令牌的内容似乎很奇怪。
    猜你喜欢
    • 1970-01-01
    • 2020-04-22
    • 2019-06-29
    • 1970-01-01
    • 1970-01-01
    • 2018-01-03
    • 1970-01-01
    • 2018-11-20
    • 2017-08-09
    相关资源
    最近更新 更多