繁体   English   中英

使用宏定义包含文件

[英]Using a macro to define an include file

长话短说,我正在编写一些代码,这些代码需要基于各种配置选项的不同头文件。 我可以做这样的事情:

#if OPTION == A
#include "relative/path/to/file/a.hpp"
#elseif OPTION == B
#include "relative/path/to/file/b.hpp"
#elseif OPTION = ...
...
#endif

这会起作用,但对于可能不仅仅是少数文件的情况,这似乎是一个非常丑陋的解决方案。 我也可以简单地包含所有各种头文件,但这似乎也有点丑陋的解决方案,如果文件(出于某种可怕的原因)开始重新定义相同的对象,它可能会在未来造成问题。 我的想法是,像下面这样的东西会很好,特别是在其余代码是如何编写的上下文中:

#define QUOTE(str) #str
#define STRINGIFY(A,B) QUOTE(A##B)
...
#include STRINGIFY(relative/path/to/option/,OPTION)

这个问题似乎有两个方面:

  1. OPTION定义没有在STRINGIFY内正确展开。
  2. 如果路径名中有任何正斜杠,则STRINGIFY完全失败,g++ 给我一个错误,如下所示:

错误:粘贴“/”和“OPTION”没有给出有效的预处理令牌

我似乎找不到任何关于为什么/是 C++ 预处理器的坏字符的真实信息,只有几篇文章说你应该把"/"放入并依赖自动 C++ 字符串连接(这在#include语句)。 如果我只是想做一些非常愚蠢的事情,我愿意考虑设计替代方案,但我也想弄清楚为什么这不起作用。

编辑:我应该澄清一下,我正在研究最初由一组科学家设计的代码库。 合理的编码约定和对如何使用代码的典型期望完全被排除在外。 这段代码可能至少会被修改多次,通常由那些将整个职业生涯都用于编写 Fortran 77 并认为面向对象编程是一些新奇的发明,只会让你的代码更难理解的人修改。

编写宏时,必须查看预处理后的输出。 使用gcc就是-E选项。

要包含不同的文件,我将依赖您的构建工具而不是宏 voodoo。 例如,当代码是

include option

然后gcc -E -option=\"foo.h\"产生

include "foo.h"

请注意,我在这里省略了# ,否则由于找不到"foo.h" ,预处理会失败。

我想做类似的事情,四处搜索并找到了这篇文章,在尝试了一些事情之后,我想我可以帮助你。

所以,你的方法:

#define QUOTE(str) #str
#define STRINGIFY(A,B) QUOTE(A##B)
...
#include STRINGIFY(relative/path/to/option/,OPTION)

据我了解https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html不起作用,因为使用##粘贴令牌时,结果必须是有效令牌,其中类似于path/to/file.hpp不是有效的预处理令牌。

现在,我认为您只需要一个包含路径和要替换的令牌的宏。 好吧,如果您使用-I标志,您实际上并不需要添加相对路径。 您的宏可能看起来像#define myMacro relative/path/to/file/OPTION.hpp ,然后您只需要定义OPTION并将其传递给一个宏,以便OPTION被其值替换,然后另一个宏被字符串化。 此处描述了这两个级别的宏https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html#Stringizing

以下示例将说明这两种情况(带/不带-I标志)。

考虑这个目录结构:

.   
|-- a.c 
|-- headers
|   |-- A.hpp
|   `-- B.hpp
`-- makefile

其中交流:

#define header OPTION.hpp
#define xstr(x) #x
#define str(x) xstr(x)
#include str(header)

生成文件:

PATH_OPTION ?= headers/A
OPTION ?= A

.PHONY: all 
all: a.c 
        cpp -D OPTION=${PATH_OPTION} $<
        cpp -I./headers -D OPTION=${OPTION} $<

A.hpp

#warning Including A.hpp
1   

B.hpp

#warning Including B.hpp
2   

有了这个,您可以调用make默认情况下将包含headers/A.hpp并且您应该能够看到两种方法(带/不带-I标志)工作并打印到标准输出相应的警告。

要包含headers/B.hpp ,您可以根据您采用的方法make OPTION=Bmake PATH_OPTION=headers/B

我也尝试使用g++而不是cpp ,它也可以。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM