从预处理器宏中包含
Include from preprocessor macro
我正在尝试包含一个由 pre-processor 宏构建的文件,但似乎 运行 由于有关令牌的规则而进入墙。我在这里使用答案作为参考:Concatenate string in C #include filename,但我的情况不同之处在于我用来构造包含的定义中有小数点。这是我目前无法通过预处理器阶段的内容:
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
并相应地重命名 header 它会起作用(但不适合我使用,因为我无法控制 header 文件的名称实际项目使用),但 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
。我不确定为什么这是可以接受的,因为生成的标记是相同的,但确实如此。
我仍然希望有一个解决方案,允许我只定义不带下划线的版本号,所以我会推迟接受这个答案,以防有人能想出一个更优雅的解决方案(并且适用于反正不需要下划线的人)
如果您将 -DVERSION=1.1.0
作为 compile-line 参数传递,而不是在源代码中将其 hard-wiring 传递,那么没有什么可以阻止您使用 [=16 传递第二个定义=] 或 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
的字符串化版本,而不是尝试在源代码中构造 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=x.y.z 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
行放在一个单独的小header里,这样在需要header版本的时候就可以包含了。如果还需要默认设置,那么将代码放入单独的 header 以供重用的重要性就会增加。该程序的源代码可能包含:
#include "other_version.h"
并且 header 会安排包含正确的文件,大致如图所示。
一旦您不再考虑令牌串联,这就很容易了。字符串化适用于任何标记序列,因此无需强制其参数成为单个标记。您确实需要一个额外的间接寻址以便扩展参数,但这是正常的。
唯一的技巧是写序列时不要有空格,这就是 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)
有关详细说明,请参阅 。
我正在尝试包含一个由 pre-processor 宏构建的文件,但似乎 运行 由于有关令牌的规则而进入墙。我在这里使用答案作为参考:Concatenate string in C #include filename,但我的情况不同之处在于我用来构造包含的定义中有小数点。这是我目前无法通过预处理器阶段的内容: 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
并相应地重命名 header 它会起作用(但不适合我使用,因为我无法控制 header 文件的名称实际项目使用),但 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
。我不确定为什么这是可以接受的,因为生成的标记是相同的,但确实如此。
我仍然希望有一个解决方案,允许我只定义不带下划线的版本号,所以我会推迟接受这个答案,以防有人能想出一个更优雅的解决方案(并且适用于反正不需要下划线的人)
如果您将 -DVERSION=1.1.0
作为 compile-line 参数传递,而不是在源代码中将其 hard-wiring 传递,那么没有什么可以阻止您使用 [=16 传递第二个定义=] 或 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
的字符串化版本,而不是尝试在源代码中构造 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=x.y.z 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
行放在一个单独的小header里,这样在需要header版本的时候就可以包含了。如果还需要默认设置,那么将代码放入单独的 header 以供重用的重要性就会增加。该程序的源代码可能包含:
#include "other_version.h"
并且 header 会安排包含正确的文件,大致如图所示。
一旦您不再考虑令牌串联,这就很容易了。字符串化适用于任何标记序列,因此无需强制其参数成为单个标记。您确实需要一个额外的间接寻址以便扩展参数,但这是正常的。
唯一的技巧是写序列时不要有空格,这就是 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)
有关详细说明,请参阅