我想弄清楚的是这样的事情(用 C 写的):
#define FOO 15
#define BAR 23
#define MEH (FOO / BAR)
是允许的吗?我希望预处理器替换
的每个实例MEH
与
(15 / 23)
但我不确定这会有效。当然,如果预处理器只通过代码一次,那么我认为它不会按照我喜欢的方式运行。
我找到了几个类似的例子,但所有这些都让我理解得太复杂了。如果有人可以帮我解决这个简单的问题,我将永远感激不尽!
答案 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编译器也适用。我觉得它非常灵活。