包含来自预处理器的宏

时间:2018-03-26 17:29:13

标签: c preprocessor

我正在尝试包含一个由预处理器宏构建的文件,但由于有关令牌的规则,它似乎正在运行到墙上。我在这里使用了答案作为参考:Concatenate string in 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.1.0是有效的1.1.0;它是preprocessing number的结果串联无效。无论如何,无法构建包含的问题仍然存在。

3 个答案:

答案 0 :(得分:2)

通过一些实验,我想出了一个解决方案,虽然不理想,但仍然可行。

<section id="pageMain">
  <div id="archive">
    <ul>
      <li>MARCH - 2018</li>
      <li>FEBUARY - 2018</li>
      <li>JANUARY - 2018</li>
      <li>DECEMBER - 2017</li>
      <li>NOVEMBER - 2017</li>
    </ul>
  </div>
  <div id="aboutGame">
    <span>
			As if awakening from a deep sleep, you find yourself in a strange, contradictory world of ancient ruins and advanced technology. Tasked by your creator with solving a series of increasingly complex puzzles, you must decide whether to have faith, or to ask the difficult questions: Who are you? What is your purpose and what are you going to do about it? </span>
    <img src="http://cdn.akamai.steamstatic.com/steam/apps/257510/ss_ded5cd1a34df5b4d9015f71caf35db247b2579c4.1920x1080.jpg?t=1498680189" height="500px" width="800px" />
  </div>
</section>

我粘贴#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.0other。我不确定为什么这是可以接受的,因为结果令牌是相同的,但它就是。

我仍然希望有一个解决方案,只允许我定义没有下划线的版本号,所以我会推迟接受这个答案,以防有人能提出更优雅的解决方案(适用于那些人不管怎么说都不需要下划线)

答案 1 :(得分:2)

一旦你停止考虑令牌连接,这很容易。字符串化适用于任何标记序列,因此无需强制其参数成为单个标记。你需要一个额外的间接,以便扩展参数,但这是正常的。

唯一的技巧是编写没有空格的序列,这是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

答案 2 :(得分:1)

如果您将-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=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行放入一个单独的小标题中,以便在需要版本标题时可以包含它。如果还需要默认设置,则会增加将代码放入单独的标头以供重用的重要性。该程序的源代码可能包含:

#include "other_version.h"

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