【发布时间】:2020-11-07 18:42:09
【问题描述】:
此 C 语言程序定义了宏 START 和 END,它们生成运行时函数执行信息。动作 TRACE_START 和 TRACE_END 当然可以是任何东西,例如推送和弹出堆栈、动态分析等。此外,没有理由不能运行时可配置操作行为。这为某些类型的软件产品提供了许多有吸引力的可能性。
不利的一面是,将函数的左大括号和右大括号从 f(){} 重新定义为 f()START...END 可能会破坏许多自动工具。 接受这种情况, 这样做有什么影响?这种使用宏处理器是否可移植?
下面的代码使用 gcc --pedantic 正确编译。
#include <stdio.h>
#define START {TRACE_START
#define END TRACE_END}
#define TRACE_START printf("ENTERING %s\n", __func__);
#define TRACE_END printf("LEAVING %s\n", __func__);
int func()
START
printf ("Hello World %s\n");
END
int main()
START
func();
END
并产生输出
ENTERING main
ENTERING func
Hello World
LEAVING func
LEAVING main
提前感谢您的富有洞察力的 cmets。
【问题讨论】:
-
预处理器不应该关心其扩展结果的语法,编译器也不应该关心预处理器的魔法产生了它的输入。 AFAIK 这是完全合法的,虽然很可怕。
-
代码原样严格符合 C 标准定义它,因此在这个意义上它是可移植的。正如您所注意到的,它可能不适用于自动工具。通常也不能依赖它与其他源代码一起使用,因为其他源代码可能对
START、END等有自己的用途。随着您作为程序员的进步,您通常会学会避免这样的杂牌。几乎没有理由删除{和}。只需将START和END宏与{和}放在一起,而不是代替它们,就可以检测例程。 -
请注意,没有理由期望任意函数会到达
END,因为函数可能会返回return语句(或longjmp或exit或abort等)。 -
甚至要求非空函数不能到达
END。 -
它是“可移植的”,因为每个符合标准的编译器都必须接受它。但是,它非常非常规,并且正如您所指出的,它可能会与 IDE、代码分析工具、代码格式化程序和其他尝试阅读代码的人进行不良交互。
标签: c macros c-preprocessor