C宏-动态#include

p3rjfoxz  于 2023-04-29  发布在  其他
关注(0)|答案(5)|浏览(120)

我试图弄清楚如何使用GCC为#include语句构建变量字符串。
我的想法是,对于我编写的每个源代码模块,我希望包含一个头文件,一个动态生成的C源代码,它是在构建过程的早期创建的。
生成此文件不是问题。不幸的是,包括它在内。
到目前为止我所拥有的是(身份。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)是这篇文章的结果。
不幸的是,这不起作用,我留下了错误:

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

我认为问题在于include语句缺少引号。有什么想法吗?

iqxoj9l9

iqxoj9l91#

这是在Linux源代码树中完成的;参见compiler-gcc的第125行。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

a. c

#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等,并将其替换为已知的include名称。
任何一种技术都适合生成测试夹具等。但是,对于编译器功能发现,这是一种更好的方法。对于使用IDE的程序员来说,这可能是他们唯一的选择。

xjreopfe

xjreopfe2#

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

"Hello" " World"

将被C++解析器视为单个字符串。然而,#include是预处理器的一部分,因此无法利用这一事实。
老答案:
你为什么要这么做

{ #str, str ## .iden }

我确信这不是预处理器语法;你希望通过这个达到什么目的?你是否尝试过:

str ## .iden

“{”可以解释您得到的错误。

yx2lnoni

yx2lnoni3#

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

rbpvctlc

rbpvctlc4#

暂时跳过整个包含语法的事情,我不明白你的代码想做什么。你说:

# 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)
ylamdve6

ylamdve65#

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

相关问题