是否可以在宏内部定义宏?

时间:2018-01-24 20:47:26

标签: c macros

我想使用像这样的宏参数:

  #define D(cond,...) do{         \
    #if cond                      \
    #define YYY 1                 \
    #else                         \
    #define YYY 0                 \
  } while(0)

有可能吗?

UPD
也许当源被预处理两次时:gcc -E source.c | gcc -xc -接下来将起作用:

#define D(cond,...) #define YYY cond&DEBUG
#if YYY
#define D(...) printf( __VA_ARGS__ )
#else
#define D(...)
#endif

6 个答案:

答案 0 :(得分:4)

这是不可能的。了解GNU cpp preprocessor和C11标准(即n1570),然后查看hereC preprocessor(概念上至少)在编译器的其余部分(它获取translation unit预处理形式)之前运行。顺便说一句,对于文件foo.c,您可以使用gcc -C -E foo.c > foo.i(使用GCC)获取其预处理表单foo.i,然后您可以检查foo.i -since它是一个文本文件 - 带有寻呼机或编辑器。

但是,可生成.c个文件(生成C代码是一种常见做法,至少从20世纪80年代开始;例如yacc,{{3} },bisonrpcgen,....;许多大型软件项目使用C或C ++代码的专用生成器......)。您可以考虑使用其他工具(可能是swig预处理器(或GPP)或其他一些程序或脚本来生成C文件(来自其他程序)。再看看GNU m4(它可能有类似于你的目标)。

您可能需要为此目的配置autoconf工具,例如为build automation修改Makefile

答案 1 :(得分:3)

不,这是不可能的。

在翻译期间,所有预处理指令(#define#include等)都会在任何宏扩展发生之前执行,因此如果宏扩展为预处理指令,它不会被解释为 - 它将被解释为(无效的)源代码。

答案 2 :(得分:3)

正如其他人指出的那样,这是不可能的,但有一个解决方法:

int YYY;
/* global scope variables are sometimes considered bad practice... */
#define D(cond,...) do{         \
  if (cond) {                   \
  YYY = 1;                      \ 
  }                             \
  else {                        \
  YYY = 0;                      \
  }                             \
} while(0)

使用优化标记(例如:gcc/clang -O3),它将替换死代码,就像它是一个宏一样。显然你可能想要改变YYY的类型,但你似乎像布尔一样使用它。

答案 3 :(得分:2)

不,因为C 2011 [N1570] 6.10.3.4 3说,关于宏替换,“结果完全宏替换的预处理令牌序列不会被处理为预处理指令,即使它类似于一个,......”

答案 4 :(得分:1)

不,你不能。 C预处理器无法知道运行时会发生什么。

预处理程序在编译之前会经历程序,并替换使用其指定值定义的每个宏。

答案 5 :(得分:0)

这是一些穷人的代码生成,因为将另一个工具集成到项目中是多余的。

像这样定义一个宏,根据您的需要进行扩展:

#define NESTED              /* Comment out instead of backslash new lines.
*/                          /*
*/  UNDEF   REPLACED        /*
*/                          /*
*/  IFDEF   CONDITION       /*
*/  DEFINE  REPLACED  1     /*
*/  ELSE                    /*
*/  DEFINE  REPLACED  0     /*
*/  ENDIF

您的 NESTED 版本可以是类似函数的宏,而 REPLACED 可以具有更详细的主体。

CONDITION 和名为 macros 的指令没有定义。

DEFINE CONDITION 控制 NESTED 在编译时获得哪个值,类似于正常的 #ifdef 用法:

DEFINE  CONDITION
NESTED
int i = REPLACED;        //i == 1

UNDEF  CONDITION
NESTED
int z = REPLACED;        //z == 0

使用 NESTED 和其他宏的源代码将无法编译。要生成可以使用所选选项编译的 .c.cpp 文件,请执行以下操作:

gcc   -E -CC   source.c  -o temporary.c
gcc   -E                                                  \
   -DDEFINE=\#define  -DUNDEF=\#undef                     \
   -DIFDEF=\#ifdef    -DELSE=\#else    -DENDIF=\#endif    \
   temporary.c  -o usableFile.c

rm temporary.c     #remove the temporary file

-E 表示仅预处理,不编译。第一个 gcc 命令扩展 NESTED 和源中所有正常定义的宏。由于未定义 DEFINEIFDEF 等,它们及其未来的参数在 temporary.c 文件中保留为文字文本。

-CC 使注释保留在输出文件中。在预处理器用它的主体替换 NESTED 之后,temporary.c 在单独的行中包含指令宏,并带有注释。当下一个 gcc 命令的注释被删除时,换行符仍然是标准的。

# 在不带参数的宏的主体中被接受。但是,与宏不同,指令不会在扩展时重新扫描和执行,因此您需要另一个预处理器传递来使嵌套定义工作。所有与延迟定义相关的预处理也需要延迟,并立即提供给预处理器。否则,稍后传递中所需的指令和参数将被消耗并从前一个传递中的代码中删除。

第二个 gcc 命令将 -D 宏替换为延迟指令,使所有这些宏都可以在下一轮开始的预处理器中使用。指令及其参数不会在同一个 gcc 命令中重新扫描,而是在 usableFile.c 中保留为文字文本。

编译 usableFile.c 时,预处理器会执行延迟指令。