Cpp:如何理解和/或调试复杂的宏?

时间:2019-01-12 09:20:15

标签: c macros c-preprocessor variadic-macros stringification

我正在尝试学习我发现不太容易的预处理器技巧(Can we have recursive macros?Is there a way to use C++ preprocessor stringification on variadic macro arguments?C++ preprocessor __VA_ARGS__ number of argumentsVariadic macro trick,...)。

我知道-E选项可以查看预处理程序整个遍历的结果,但是我想知道,如果存在的话或者可以逐步查看结果的方法。确实,有时很难跟踪当宏调用宏调用宏时发生的情况...具有禁用上下文的机制,将其涂成蓝色...简而言之,我想知道一种带有断点和其他功能的预处理器调试器工具已经存在。

(不要回答这种预处理指令的使用是危险的,丑陋的,可怕的,不是C语言中的好习惯,会产生无法读取的代码……我知道这不是问题,

3 个答案:

答案 0 :(得分:2)

是的,该工具是Eclipse IDE的功能之一。我认为访问该功能的默认方法是将鼠标悬停在您要查看扩展的宏上(这将显示完整的扩展),然后按键盘上的F2(出现一个弹出窗口,可让您逐步浏览每个宏扩展)。

当我使用此工具了解有关宏的更多信息时,它非常有帮助。只需少量练习,您就不再需要它。

万一有人对如何使用此功能感到困惑,我在Eclipse文档here上找到了一个教程。

答案 1 :(得分:1)

这个answer与另一个问题有关。

当您做一些奇怪的预处理技巧(合法的)时,要求编译器生成预处理形式(例如,如果使用GCC,则使用gcc -C -E并查看该预处理形式很有用。 / p>

在实践中,对于源文件foo.c,有时(有意义)是使用foo.i获得其预处理形式gcc -C -E foo.c > foo.i并查看该foo.i

有时候,甚至没有行信息也可以得到foo.i。这里的技巧(删除以#开头的行中包含的行信息)是:

gcc -C -E foo.c | grep -v '^#' > foo.i

然后您可以indent foo.i进行编译,例如与gcc -Wall -c foo.i;您将在预处理文件中找到错误位置,并且可以了解如何获取该错误,然后返回到预处理器宏(或它们的调用)。

请记住,C preprocessor主要是在文件级运行的文本转换。不可能单独宏扩展几行 (因为先前的行可能与#if#define结合使用-也许在先前的#include-d files-或preprocessor options,例如-DNDEBUG传递给gccg++。在Linux上,请参见feature_test_macros(7)

assert是一个已知的扩展示例,在有无-DNDEBUG传递给编译器的情况下进行编译时,其工作原理有所不同。 assert(i++ > 0)的含义(编码上的错误事情)取决于它的含义,并说明了宏扩展不能在本地完成(并且您可能会想像一些先前拥有#define NDEBUG 1的标头,即使它当然很差)口味)。

另一个宏扩展依赖于上下文的示例(实际上非​​常常见)是使用__LINE____COUNTER__的任何宏 ...

NB。您不需要Eclipse就足够了,source code editor就足够了(我的偏爱是emacs,但要随心所欲):对于预处理任务,您可以使用编译器。

答案 2 :(得分:0)

查看宏问题的唯一方法是添加选项,该选项将在编译完成后保留临时文件。对于gcc,它是-save-temps选项。您可以打开.i文件和展开的宏。

IDE索引器(例如Eclipse)不会有太大帮助。直到发生错误,它们才会扩展宏(与其他答案一样)。 enter image description here