gpt4 book ai didi

c++ - 使用宏构造#include 指令的路径

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:21:01 27 4
gpt4 key购买 nike

我希望包含由宏为我的程序的目标配置相关部分动态创建的文件路径。

例如,我想构造一个像这样调用的宏:

#include TARGET_PATH_OF(header.h)

这将扩展为如下所示:

#include "corefoundation/header.h"

当为 OSX 配置源时(在本例中)

到目前为止所有的尝试都失败了。我希望有人以前做过这个?

无效示例:

#include <iostream>
#include <boost/preprocessor.hpp>

#define Dir directory/
#define File filename.h

#define MakePath(f) BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
#define MyPath MakePath(File)

using namespace std;

int main() {
// this is a test - yes I know I could just concatenate strings here
// but that is not the case for #include
cout << MyPath << endl;
}

错误:

./enableif.cpp:31:13: error: pasting formed '/filename', an invalid preprocessing token
cout << MyPath << endl;
^
./enableif.cpp:26:16: note: expanded from macro 'MyPath'
#define MyPath MakePath(File)
^
./enableif.cpp:25:40: note: expanded from macro 'MakePath'
#define MakePath(f) BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
^
/usr/local/include/boost/preprocessor/cat.hpp:22:32: note: expanded from macro 'BOOST_PP_CAT'
# define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b)
^
/usr/local/include/boost/preprocessor/cat.hpp:29:36: note: expanded from macro 'BOOST_PP_CAT_I'
# define BOOST_PP_CAT_I(a, b) a ## b
^
1 error generated.

最佳答案

我倾向于同意 utnapistim's answer 中的评论你不应该这样做,即使你可以。但是,事实上,您可以使用符合标准的 C 编译器。 [注1]

有两个问题需要克服。第一个是您不能使用 ## 运算符来创建不是有效预处理器 token 的内容,并且路径名不符合有效预处理器 token 的条件,因为它们包含 /. 字符。 (如果 token 以数字开头,. 会没问题,但 / 将永远不起作用。)

您实际上不需要连接标记以便使用 # 运算符将它们字符串化,因为该运算符将字符串化整个宏参数,并且该参数可能包含多个标记。但是,stringify 尊重空格 [注 2],因此 STRINGIFY(Dir File) 将不起作用;它将导致 "directory/filename.h" 并且文件名中的多余空间将导致 #include 失败。因此,您需要连接 DirFile,不带任何空格。

下面通过使用一个类似函数的宏来解决第二个问题,它只返回它的参数:

#define IDENT(x) x
#define XSTR(x) #x
#define STR(x) XSTR(x)
#define PATH(x,y) STR(IDENT(x)IDENT(y))

#define Dir sys/
#define File socket.h

#include PATH(Dir,File)

警告:(感谢@jed 解决了这个问题。)如果连接的字符串包含在别处定义为宏的标识符,那么此处将发生意外的宏替换。应注意避免这种情况,特别是如果 Dir 和/或 File 不受控制(例如,通过在编译器调用中定义为命令行参数).

您还需要注意,某些实现可能会定义可能以类似 token 的方式出现在文件路径中的单词。例如,GCC 可能会定义名称为 unixlinux 的宏,除非使用显式 C 标准(这不是默认值)调用它。这可能由 platform/linux/my-header.h 甚至 linux-specific/my-header.h 等路径触发。

为避免这些问题,如果您使用此 hack,我建议您:

  • 您使用符合 C(或 C11)标准的编译器设置,并且

  • 您将序列放在源文件的早期,最好是在包含任何其他 header 之前,或者至少是在标准库之外的任何 header 之前。

此外,如果您可以编写不带空格的串联,则您不需要复杂的 IDENT 宏。例如:

#define XSTR(x) #x
#define STR(x) XSTR(x)

#define Dir sys
#define File socket.h

#include STR(Dir/File)

注意事项

  1. 我在 godbolt 上使用 clang、gcc 和 icc 进行了尝试.我不知道它是否适用于 Visual Studio。

  2. 更准确地说,它半尊重空格:空格被转换为单个空格字符。

关于c++ - 使用宏构造#include 指令的路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48613747/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com