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

时间:2011-11-01 20:56:07

标签: c c-preprocessor

我想弄清楚的是这样的事情(用 C 写的):

#define FOO 15
#define BAR 23
#define MEH (FOO / BAR)

是允许的吗?我希望预处理器替换

的每个实例
MEH

(15 / 23)

但我不确定这会有效。当然,如果预处理器只通过代码一次,那么我认为它不会按照我喜欢的方式运行。

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

6 个答案:

答案 0 :(得分:30)

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

答案 1 :(得分:26)

答案是“是”,另外两个人也正确地说过了。

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

  

6.10.3.4重新扫描和进一步更换

     

替换列表中的所有参数都被替换后   #和##处理已经发生,所有地标预处理令牌都被删除。   然后,生成预处理令牌序列   重新扫描,以及所有后续的预处理令牌   源文件,用于替换更多宏名称。

     

如果在此扫描期间找到要替换的宏的名称   替换列表(不包括源文件的其余部分   预处理令牌),它没有被替换。此外,如果有任何嵌套   替换遇到被替换的宏的名称,它不是   更换。这些未替换的宏名称预处理标记是否定的   更长的可用于进一步更换,即使它们以后   (重新)在宏名称预处理令牌的上下文中进行检查   否则就会被取代。

     

由此产生的完全宏替换的预处理标记序列   即使它类似,也不会被处理为预处理指令   一个,但其中的所有pragma一元运算符表达式都是   按照下面6.10.9的规定处理。

答案 2 :(得分:14)

是的,它会起作用。


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

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

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

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

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

operator#stringize参数:

#define str(x) #x
str(test); // would translate to "test"

运算符##连接两个参数

#define concat(a,b) a ## b
concat(hello, world); // would translate to "helloworld"

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

__LINE__, __FILE__, __cplusplus, etc

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

  • 注意宏扩展

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

#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))

答案 3 :(得分:2)

我想添加一个让我绊倒的陷阱。

函数式宏不能执行此操作。

使用时不编译的示例:

#define FOO 1
#define FSMACRO(x) FOO + x

答案 4 :(得分:0)

是的,这是支持的。并且使用了很多!

要注意的一件重要事情是确保你对表达方式进行包容,否则你可能会遇到令人讨厌的问题!

#define MEH FOO/BAR

// vs

#define MEH (FOO / BAR)

// the first could be expanded in an expression like 5 * MEH to mean something 
//   completely different than the second

答案 5 :(得分:0)

是的,此功能还有另一个优势。您可以保留一些未定义的宏,并在编译命令中将其值设置为另一个宏的名称

#define STR "string"
void main() { printf("value=%s\n", VALUE); }

在命令行中,您可以说宏“ VALUE”从另一个宏“ STR”获取值:

$ gcc -o test_macro -DVALUE=STR main.c
$ ./test_macro

输出:

value=string

此方法对于Windows上的MSC编译器也适用。我觉得它非常灵活。