C 宏 - 动态#include

发布于 2024-11-05 00:45:48 字数 1037 浏览 0 评论 0原文

我试图弄清楚如何使用 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)是 这篇文章

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

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

我认为问题是 include 语句缺少引号..有什么想法吗?

I'm trying to figure out how to build a variable string for the #include statement using GCC.

The idea is that for each source module I have written, I want to include as a header, a dynamically generated C source, that was created earlier in the build process.

Generating this file is not an issue. Including it, unfortunately, is.

What I have so far is (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

Ideally, this would be used like so (main.c):

//main.c

# include "identities.h"

int main() {return 0;}

Which would be expanded in a single pass by the preprocessor before compilation to yield:

//main.c (preprocessed)

# include "main.c.iden"

int main() {return 0;}

The two levels of indirection I'm using (PASTER and EVALUATOR) are a result of this post.

Unfortunately, this is not working and I am left with the error:

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

I think the problem is that the include statement is missing quotes.. Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

情泪▽动烟 2024-11-12 00:45:48

这是在 Linux 源代码树中完成的;请参阅 旧版编译器-gcc.h 的第 125 行

#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 预定义值。 <代码>回声| g++ -dM -E - 将给出一个列表。

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

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

This was done in the Linux source tree; See line 125 of and older 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__)

I'm trying to figure out how to build a variable string for the #include statement using GCC.

This token pastes the value of __GNUC__ to a string; "linux/compiler-gcc" __GNUC__ ".h" and then stringifies the result. This maybe a gcc pre-processor extension.

Here is an example,

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;
}

Here are two compiles,

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

The output of either compile gives expected result.

As with the Linux source, you can key off of gcc pre-defined values. echo | g++ -dM -E - will give a list.

For your case, you can use the makefile to pass a define to the compile to allow dynamic inclusion of the generated header without altering the source. But then a simple alternative is just to run sed, etc on a template source file and replace it with the known include name.

Either technique is good for generating test fixtures, etc. However, for compiler feature discovery, this is a better method. For programmers who use IDEs, this might be their only choice.

柠栀 2024-11-12 00:45:48

我相当确定你不能做你想做的事,__FILE__返回一个字符串,##适用于令牌,并且没有CPP字符串连接预处理器宏。通常,由于两个连续的字符串(例如)

"Hello" " World"

将被 C++ 解析器视为单个字符串,因此可以解决此问题。但是,#include 是预处理器的一部分,因此无法利用这一事实。

旧答案:

你为什么要这样做

{ #str, str ## .iden }

我确信这不是预处理器语法;您希望通过此实现什么目标?您是否尝试过:

str ## .iden

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

I am fairly certain you can't do what you want, __FILE__ returns a string and ## works on tokens and there is no CPP string concat preprocessor macro. Normally this is gotten around due to the fact that two strings in succession e.g.

"Hello" " World"

will be treated as a single string by the C++ parser. However, #include is part of the preprocessor, and thus cannot take advantage of that fact.

Old answer:

Why are you doing this

{ #str, str ## .iden }

I'm certain that's not preprocessor syntax; what do you hope to achieve via that? Have you tried just:

str ## .iden

A '{' could explain the error you are getting.

紧拥背影 2024-11-12 00:45:48

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

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

你给它 main.c 并期望 "main.c.iden",但是返回 {"main.c", main.c。伊登}

相反,您在寻找这个吗?

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

Skipping the whole inclusion syntax thing for a while, I don't understand what your code is trying to do. You say:

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

You give it main.c and expect "main.c.iden", but that returns {"main.c", main.c.iden }.

Are instead you looking for this?

#define PASTER2(str) #str
#define PASTER(str) PASTER2(str ## .iden)
微凉徒眸意 2024-11-12 00:45:48

Boost 预处理器库中的 BOOST_PP_STRINGIZE 怎么样?它是专门为在名称周围添加引号而设计的。

What about BOOST_PP_STRINGIZE from the Boost Preprocessor library . It is specifically made to add quotes around a name.

帅气称霸 2024-11-12 00:45:48

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

You cannot use preprocessor like this. You have to supply a filename to the #include directive, it can't be some other macro.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文