C宏定义可以引用其他宏吗?

lla*_*ais 40 c c-preprocessor

我想弄清楚的是,如果像这样的东西(用C语写):

#define FOO 15
#define BAR 23
#define MEH (FOO / BAR)
Run Code Online (Sandbox Code Playgroud)

被允许?我希望预处理器替换每个实例

MEH
Run Code Online (Sandbox Code Playgroud)

(15 / 23)
Run Code Online (Sandbox Code Playgroud)

但我不太确定它会起作用.当然,如果预处理器只通过代码一次,那么我认为它不会按照我想要的方式运行.

我找到了几个类似的例子,但所有这些都让我理解得太复杂了.如果有人能帮我解决这个简单的问题,我将永远感激不尽!

Mys*_*ial 36

简短回答是的.您可以像这样嵌套定义和宏 - 只要它不是递归的,就可以使用多个级别.

  • @DavidHeffernan:顺序并不重要,所有重要的是在出现"MEH"时定义"MEH","FOO"和"BAR".预处理器首先用`(FOO/BAR)`替换'MEH`,然后重新开始,用`15`替换'FOO`然后用`23`替换`BAR` (12认同)
  • 订单重要吗?可以'MEH`首先被#defined? (6认同)

Kei*_*son 27

答案是"是",另外两个人也正确地这么说.

至于为什么答案是肯定的,血淋淋的细节在C标准第6.10.3.4节"重新扫描和进一步替换"中.OP可能不会从中受益,但其他人可能会感兴趣.

6.10.3.4重新扫描和进一步更换

在替换列表中的所有参数都已被替换并且#和##处理已经发生之后,将删除所有地标标记预处理标记.然后,重新扫描生成的预处理标记序列以及源文件的所有后续预处理标记,以替换更多的宏名称.

如果在替换列表的扫描期间找到要替换的宏的名称(不包括源文件的其余预处理标记),则不会替换它.此外,如果任何嵌套替换遇到要替换的宏的名称,则不会替换它.这些未替换的宏名称预处理令牌不再可用于进一步替换,即使它们稍后(重新)检查在其中否则将替换该宏名称预处理令牌的上下文中.

得到的完全宏替换的预处理标记序列不会被处理为预处理指令,即使它类似于1,但是其中的所有编译指示一元运算符表达式然后按照下面的6.10.9中的规定进行处理.


Sau*_*eil 14

是的,它会起作用.


但是对于您的个人信息,这里有一些关于可能对您有帮助的宏的简化规则(它超出了范围,但将来可能对您有所帮助).我会尽量保持简单.

  • 定义按照包含/读取的顺序"定义".这意味着您不能使用之前未定义的定义.

  • 有用的预处理器关键字:#define,#undef,#else,#elif,#ifdef,#ifnf,#if

  • 您可以在宏中使用任何其他以前的#define.他们将扩大.(就像在你的问题中)

  • 函数宏定义接受两个特殊运算符(#和##)

operator#stringize参数:

#define str(x) #x
str(test); // would translate to "test"
Run Code Online (Sandbox Code Playgroud)

operator ##连接两个参数

#define concat(a,b) a ## b
concat(hello, world); // would translate to "helloworld"
Run Code Online (Sandbox Code Playgroud)

您可以使用一些预定义的宏(来自语言):

__LINE__, __FILE__, __cplusplus, etc
Run Code Online (Sandbox Code Playgroud)

请参阅您的编译器部分,以获得广泛的列表,因为它不是"跨平台"

  • 注意宏观扩张

您将看到人们在定义宏时使用圆括号"()"的日志.原因是当你调用一个宏时,它会"按原样"扩展

#define mult(a, b) a * b
mult(1+2, 3+4); // will be expanded like: 1 + 2 * 3 + 4 = 11 instead of 21.
mult_fix(a, b) ((a) * (b))
Run Code Online (Sandbox Code Playgroud)