关注我的{duplicate)question(以及StoryTeller的建议)
为什么预处理器宏忽略括号中的函数名?
#include <stdio.h>
#include <stdlib.h>
#define abs(x) ((x))
int main(void)
{
printf("%d\n", abs(-1)); // output: -1
printf("%d\n", (abs)(-1)); // output: 1
return 0;
}
这是在标准中定义的吗?
答案 0 :(得分:9)
预处理器的宏替换指定如下:
6.10.3 Macro replacement / p10 - 强调我的:
表单
的预处理指令# define identifier lparen identifier-list<opt> ) replacement-list new-line # define identifier lparen ... ) replacement-list new-line # define identifier lparen identifier-list , ... ) replacement-list new-line
使用参数定义类似函数的宏,其用法类似 语法上的函数调用。参数由。指定 可选的标识符列表,其范围从它们的范围扩展 在标识符列表中声明,直到换行符 终止#define预处理指令。 每个后续 类似函数的宏名称的实例后跟一个(作为下一个 预处理令牌引入了预处理令牌的序列 由定义中的替换列表替换(an 调用宏)。替换的预处理序列 令牌由匹配的预处理令牌终止,跳过 插入匹配的左右括号预处理对 令牌。在预处理令牌组成的序列中 调用类似函数的宏,新行被认为是正常的 白色空间。
它以粗体显示它。要进行替换,宏名称后面的下一个预处理标记必须是(
。当它是)
时,例如当宏在括号中时,不会发生替换。
这样我们只能在括号中使用函数名,这个表达式与函数的指示符相同。
答案 1 :(得分:0)
为什么呢?因为 C预处理器不能使用C语言!
C预处理器被认为是纯文本替换工具,几乎不足以为C程序员提供简单的方法
定义粘贴到程序中的常量
将文件(即标题)的内容直接粘贴到程序
提供了一种简单的方法来创建简单的代码模板,再次将其粘贴到程序中
这些都不包括对C语法的任何认识!它是纯文本操作。
相反,你可以做这样的事情
#define CLASS(name, base) typedef struct name name;\
struct name {\
base super;
#define END_CLASS };
CLASS(foo, bar)
int baz;
END_CLASS
请注意,在展开{
宏时,预处理器将生成不匹配的CLASS
令牌,在展开}
宏时,预处理器将生成无法匹配的END_CLASS
令牌。
因此,使用宏的语法与调用函数的语法无关。您可以通过多种不同的方式调用C函数(foo()
,foo ()
,(foo)()
,(**(*foo) ) ()
等),因为C语言处理函数的表达式,并定义了什么当您将其名称放在括号中时(它会隐式转换为指向它的指针),取消引用它或调用它。所有这些在预处理器中都不存在,因此只有一种方法可以使用宏:foo()
,名称和(
之间没有额外的空格。
C预处理器对C语言是如此不可知,它不仅仅与C一起使用,它也常用于像FORTRAN这样的语言。 (实际上,这是非常合适的。然而,C预处理器是最好的,通常支持的东西,可以用来使FORTRAN减少痛苦。)