繁体   English   中英

从预处理器宏包含

[英]Include from preprocessor macro

我正在尝试包含一个由预处理器宏构造的文件,但是由于有关令牌的规则,它似乎碰壁了。 我在这里将答案用作参考: C #include filename中的连接字符串 ,但我的情况有所不同,因为在用于构造include的定义中有小数点。 这是我目前无法通过预处理阶段的内容:main.c:

#include <stdio.h>
#include <stdlib.h>

#define VERSION 1.1.0
#define STRINGIFY(arg) #arg
#define INCLUDE_HELPER(arg) STRINGIFY(other_ ##arg.h)
#define INCLUDE_THIS(arg) INCLUDE_HELPER(arg)

#include INCLUDE_THIS(VERSION)

int main(int argc, char **argv) {

   printf(INCLUDE_THIS(VERSION));
   fflush(stdout);
#if defined (SUCCESS)
   printf("\nSUCCESS!\n");
#endif
   return EXIT_SUCCESS;
}

other_1.1.0.h:

#define SUCCESS

如果我使用#define VERSION 1_1_0并相应地重命名了标头,它将可以工作(但我无法使用,因为我无法控制实际项目使用的标头文件的名称),但是1.1.0不是有效的预处理程序令牌。

编辑:在进一步阅读文档后,我看到1.1.0是有效的preprocessing number 导致other_1.1.0串联是无效的。 无论如何,仍然无法构建包含的问题。

经过一些试验,我想出了一个虽然不理想但可行的解决方案。

#define VERSION _1.1.0
#define STRINGIFY(arg) #arg
#define INCLUDE_HELPER(arg) STRINGIFY(other ##arg.h)
#define INCLUDE_THIS(arg) INCLUDE_HELPER(arg)

#include INCLUDE_THIS(VERSION)

我不是将other_1.1.0粘贴在一起,而是将other_1.1.0粘贴。 我不确定为什么这是可以接受的,因为生成的令牌是相同的,但是确实存在。

我仍然希望有一个解决方案,允许我只定义版本号而不使用下划线,因此我将拒绝接受此答案,以防有人可以提出更优雅的解决方案(并为那些不愿意这样做的人使用)碰巧需要下划线)

一旦您停止考虑令牌串联,这很容易。 字符串化可用于任何令牌序列,因此无需强制将其参数设为单个令牌。 您确实需要额外的间接调用,以便扩展参数,但这是正常的。

唯一的技巧是编写不带空格的序列,这就是ID的用途:

#define STRINGIFY(arg) STRINGIFY_(arg)
#define STRINGIFY_(arg) #arg
#define ID(x) x

#define VERSION 1.1.0
#include STRINGIFY(ID(other_)VERSION.h)

有关详细说明,请参见https://stackoverflow.com/a/32077478/1566221

如果您将-DVERSION=1.1.0作为编译行参数传递,而不是在源代码中进行硬连接,那么没有什么可以阻止您使用make或shell进行串联的第二个定义了。 例如,在makefile中,您可能具有:

VERSION = 1.1.0
VERSION_HEADER = other_${VERSION}.h

CFLAGS += -DVERSION=${VERSION} -DVERSION_HEADER=${VERSION_HEADER}

接着:

#include <stdio.h>
#include <stdlib.h>

#define STRINGIFY(arg) #arg
#define INCLUDE_HELPER(arg) STRINGIFY(arg)
#define INCLUDE_THIS(arg) INCLUDE_HELPER(arg)

#include INCLUDE_THIS(VERSION_HEADER)

int main(void)
{
   printf("%s\n", INCLUDE_THIS(VERSION));
#if defined (SUCCESS)
   printf("SUCCESS!\n");
#endif
   return EXIT_SUCCESS;
}

这基本上是您的代码,其中删除了#define VERSION行,并使用了VERSION_HEADER的字符串化版本,而不是尝试在源代码中构造标头名称。 您可能要使用:

#ifndef VERSION
#define VERSION 1.1.0
#endif
#ifndef VERSION_HEADER
#define VERSION_HEADER other_1.1.0.h
#endif

对于某些合适的默认后备版本,以防运行编译的人未在命令行上指定信息。 或者您可能使用#error You did not set -DVERSION=xyz on the command line而不是设置默认值。

编译时(源文件hdr59.c ):

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -DVERSION=1.1.0 \
>     -DVERSION_HEADER=other_1.1.0.h hdr59.c -o hdr59
$ ./hdr59
1.1.0
SUCCESS!
$

我会将宏的三行和#include行放入单独的小标题中,以便在需要版本标题时可以将其包含在内。 如果也需要默认设置,则将代码放入单独的标头以供重用的重要性增加了。 该程序的源代码可能包含:

#include "other_version.h"

并且该标头将安排或多或少地包含正确的文件,如图所示。

暂无
暂无

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

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