C宏 - 动态#include

时间:2011-05-03 18:04:17

标签: c macros include c-preprocessor

我正试图弄清楚如何使用GCC为#include语句构建变量字符串。

我的想法是,对于我编写的每个源模块,我希望包含一个动态生成的 C 源头,它是在构建过程的早期创建的。

生成此文件不是问题。不幸的是,包括它是。

到目前为止我所拥有的是(identities.h):

// identities.h

# define PASTER2(str)  #str
# define PASTER(str)   PASTER2(str ## .iden)
# define EVALUATOR(x)  PASTER(x)

# define IDENTITIES_FILE EVALUATOR(__FILE__)
# include IDENTITIES_FILE

理想情况下,这将被使用(main.c):

//main.c

# include "identities.h"

int main() {return 0;}

在编译之前,预处理器将在一次传递中扩展为:

//main.c (preprocessed)

# include "main.c.iden"

int main() {return 0;}

我正在使用的两个间接级别(PASTER和EVALUATOR)是this帖子的结果。

不幸的是,这不起作用,我留下了错误:

obj/win32/dbg/main.o
In file included from main.c:1:0:
identities.h:42:1: error: #include expects "FILENAME" or <FILENAME>

我认为问题在于include语句缺少引号..任何想法?

5 个答案:

答案 0 :(得分:7)

这实际上是在Linux源代码树中完成的;请参阅line 100 of compiler-gcc.h

#define __gcc_header(x) #x
#define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h)
#define gcc_header(x) _gcc_header(x)
#include gcc_header(__GNUC__)
  

我正试图弄清楚如何使用GCC为#include语句构建变量字符串。

此标记将__GNUC__的值粘贴到字符串中; “linux / compiler-gcc”__GNUC__“。h”然后将结果字符串化。这可能是 gcc 预处理器扩展。

这是一个例子,

t1.h

#define FOO 10

t2.h

#define FOO 20

交流转换器

#ifndef VERSION
#define VERSION 1
#endif
#define __gcc_header(x) #x
#define _gcc_header(x) __gcc_header(t##x.h)
#define gcc_header(x) _gcc_header(x)
#include gcc_header(VERSION)
#include <stdio.h>

int main(void)
{
        printf("FOO is %d\n", FOO);
        return 0;
}

这是两个编译,

g++ -o a a.cc
g++ -DVERSION=2 -o a a.cc

任一编译的输出都会给出预期的结果。

与Linux源代码一样,您可以键入gcc预定义值。 echo | g++ -dM -E -会列出一个清单。

对于您的情况,您可以使用 makefile 将定义传递给编译,以允许动态包含生成的标头而不更改源。但是,一个简单的替代方法就是在模板源文件上运行sed等,并用已知的包含名称替换它。

这两种技术都适用于生成测试夹具等。但是,对于编译器功能发现,这是一种更好的方法。对于使用IDE的程序员来说,这可能是他们唯一的选择。

答案 1 :(得分:3)

我相当肯定你不能做你想做的事,__ FILE__返回一个字符串,##在令牌上工作,没有CPP字符串concat预处理器宏。通常情况下这是由于连续两个字符串这样的事实,例如

"Hello" " World"
C ++解析器将

视为单个字符串,但#include是预处理器的一部分,因此无法利用这一事实。

旧答案:

你为什么这样做

{ #str, str ## .iden }

我确定这不是预处理器语法,你希望通过它实现什么?你有没有尝试过:

str ## .iden

'{'可以解释你得到的错误。

答案 2 :(得分:1)

来自Boost Preprocessor library的BOOST_PP_STRINGIZE怎么样?它专门用于在名称周围添加引号。

答案 3 :(得分:0)

暂时删除整个包含语法,我不明白你的代码试图做什么。你说:

# define PASTER(str)  { #str, str ## .iden }

您提供main.c并期望"main.c.iden",但会返回{"main.c", main.c.iden }

相反,你在寻找这个吗?

#define PASTER2(str) #str
#define PASTER(str) PASTER2(str ## .iden)

答案 4 :(得分:-1)

你不能像这样使用预处理器。你必须为#include指令提供一个文件名,它不能是其他一些宏。