gpt4 book ai didi

c++ - 可以在 C/C++ include 指令中使用环境变量吗?

转载 作者:太空狗 更新时间:2023-10-29 11:32:15 25 4
gpt4 key购买 nike

假设我有这样的文件夹布局:

.
+-- Project
+-- src
+-- foo.h
+-- foo.cpp
+-- test
+-- test_foo.c

test_foo.c 看起来是这样的:

#include "../src/foo.h"
#include <stdio.h>
#include <assert.h>

int main() {
assert(foo() == true);
printf("Test complete");
return 0;
}

有没有办法用指向源目录的变量替换 #include "../src/foo.h" 行?例如,假设在我的环境中我有一个变量:

PROJECT_SRC="./Project/src/"

然后我可以这样包含指令:

#include "PROJECT_SRC/foo.h"

这会很好,因为我可以有一个 bash 脚本来导出某个项目所需的所有路径。此外,如果该文件包含在不同的测试和构建文件中,我将不得不为每个文件设置相对路径(尽管工作量不大),这不如一个绝对路径可靠。

替代方案可能是像 CMake 这样的工具可以做到这一点。或者这被认为是不好的做法?

最佳答案

Weeelll...有点可能,但它并不漂亮,而且有一些缺陷。通常最好在构建系统中添加包含路径,例如(假设是普通的 make):

# C PreProcessor flags. This variable is used by make's implicit rules for 
# everything preprocessor-related.
CPPFLAGS += -I$(PROJECT_PATH)

#include 没有源文件中路径的 header 。这将使 make 使用 -Iyour/project/path 调用编译器,这将使编译器在 your/project/path 中查找 header .也就是说,在Makefile中你可以有

PROJECT_PATH = foo/bar
CPPFLAGS = -I$(PROJECT_PATH)

在源代码中

#include "foobar.h"

具有 #include "foo/bar/foobar.h" 的效果。

...另外,我是否看到您尝试使用 #include 源文件而不是 header ?不要走那条路;在那条路上,疯狂就在于。单独编译源文件并以通常的方式将它们链接在一起,除非您有确实好的理由不这样做。

所以,我看不出为什么要在代码的 #include 指令中直接引用项目路径;构建系统方面的唯一变化只是您必须传递 -DPROJECT_PATH=foo/bar/ 而不是 -IPROJECT_PATH=foo/bar/ 并且构造是比实际为这类东西设计的机制更脆弱。但如果你真的想这样做,那么方法如下:

你遇到的第一个问题是

#include "foo/bar/" "baz.h" // no dice.

格式错误,所以简单的方法就出来了。我们必须尝试预处理器魔法,它是这样工作的:

#define HEADER_STRING(s) #s
#define HEADER_I(path, name) HEADER_STRING(path ## name)
#define HEADER(path, name) HEADER_I(path, name)

// v-- important: no spaces allowed here!
#include HEADER(PROJECT_PATH,foobar.h)

也许从下往上开始:

#define HEADER_STRING(s) #s

从它的参数中生成一个字符串。也就是说,HEADER_STRING(foo/bar/baz.h) 扩展为 "foo/bar/baz.h"。值得注意的是,宏参数不会扩展,因此即使定义了宏 PROJECT_PATHHEADER_STRING(PROJECT_PATH) 也会扩展为 "PROJECT_PATH"。这是您尝试使用预处理器执行任何复杂操作时遇到的最常见问题之一,解决方案是添加另一个可以扩展参数的层:

#define HEADER_STRING_I(s) #s
#define HEADER_STRING(s) HEADER_STRING_I(s)

...对于 HEADER_STRING 我们不需要这个,但是它在 HEADER 中使用,所以记住这个技巧。恐怕精确的预处理器替换规则有些神秘,详细解释它们超出了 SO 答案的范围。简而言之,宏是分层展开的,当宏不展开时,技巧通常是给它们一个展开的地方,即添加另一层。

HEADER_I 然后,

#define HEADER_I(path, name) HEADER_STRING(path ## name)

将其参数粘贴在一起并将它们传递给 HEADER_STRINGHEADER_I(foo,bar) 扩展为 HEADER_STRING(foobar)。由于我上面提到的问题,HEADER_I(PROJECT_PATH,foobar.h) 扩展为 HEADER_STRING(PROJECT_PATHfoobar.h),后者又扩展为 "PROJECT_PATHfoobar. h",所以我们还需要一层对PROJECT_PATH进行扩展:

#define HEADER(path, name) HEADER_I(path, name)

这只是添加了pathname 参数要展开的地方。最后,使用 PROJECT_PATH #defined 到 foo/bar/HEADER(PROJECT_PATH,foobar.h) 展开到 "foo/bar/foobar.h",然后我们可以说

#include HEADER(PROJECT_PATH,foobar.h)

#include "foo/bar/foobar.h"PROJECT_PATH 然后可以在 makefile 中设置并通过 -DPROJECT_PATH=$(some_make_variable) 传递。

最后一个陷阱是您必须注意不要让标记之间有任何空格。

#include HEADER(PROJECT_PATH,foobar.h)

最终扩展为 "foo/bar/foobar.h"(注意空格),这是行不通的。

关于c++ - 可以在 C/C++ include 指令中使用环境变量吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27887609/

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