如何查看C预处理器输出?
在将 C 预处理器生成的输出转换为目标文件之前,如何查看它?
我想看看宏定义对我的代码做了什么。
How do I view the output produced by the C pre-processor, prior to its conversion into an object file?
I want to see what the MACRO definitions do to my code.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
或者
将为您做这件事。 -E 开关强制编译器在预处理阶段后停止,将当前所有内容吐出到标准输出。
注意:当然你必须有一些#include 指令。包含的文件也会经过预处理,因此您可能会获得大量输出。
对于 Visual C++,开关是 /E,它将预处理器输出发送到屏幕。
or
will do this for you. The -E switch forces the compiler to stop after the preprocessing phase, spitting all it’s got at the moment to standard output.
Note: Surely you must have some #include directives. The included files get preprocessed, too, so you might get lots of output.
For Visual C++ the switch is /E which spits the preprocessor output to screen.
您也可以直接调用 C 预处理器。
查看
man cpp
了解更多信息。You can also call the C Preprocessor directly.
Check out
man cpp
for more info.对于GCC来说,
还是
应该做这个工作。 -dM,正如 GNU 预处理器手册 所说的,应该生成一个列表“#define”指令用于在预处理器执行期间定义的所有宏,包括预定义的宏。
For GCC,
or
should do the job. -dM, as GNU Preprocessor manual puts it, should generate a list of ‘#define’ directives for all the macros defined during the execution of the preprocessor, including predefined macros.
这取决于您使用的编译器。
使用 GCC,您可以在命令行上指定
-E
标志,让编译器生成预处理器输出。It depends on the compiler you use.
With GCC, you can specify the
-E
flag on the command-line to let the compiler produce the pre-processor output.-save-temps
与
-E
相比,此选项的一大优点是可以很容易地将其添加到任何构建脚本中,而不会干扰构建本身有很多内容:main.c
,现在,除了正常输出
main.o
之外,当前工作目录还包含以下文件:main.i
是一个包含所需的预处理文件:<前><代码>#1“main.c”
#1“<内置>”
# 1 “<命令行>”
# 31 “<命令行>”
# 1 “/usr/include/stdc-predef.h” 1 3 4
# 32 “<命令行>” 2
# 1 “main.c”
int myfunc(int i) {
返回 i + 1;
}
main.s
是一个额外的好处,并且包含所需的生成程序集:<前><代码> .文件“main.c”
。文本
.globl myfunc
.type myfunc,@function
我的函数:
.LFB0:
.cfi_startproc
推q%rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
添加$1,%eax
弹出%rbp
.cfi_def_cfa 7, 8
雷特
.cfi_endproc
.LFE0:
.size myfunc, .-myfunc
.ident“GCC:(Ubuntu 8.3.0-6ubuntu1)8.3.0”
.section .note.GNU-stack,"",@progbits
-save-temps=obj
如果您想为大型项目执行此操作,文件数量,请考虑使用:
它将中间文件保存到与
-o
对象输出相同的目录,而不是当前工作目录,从而避免潜在的基本名称冲突。例如:
导致文件的创建:
显然,苹果计划接管世界。
-save-temps -v
关于此选项的另一个很酷的事情是,如果您添加
-v
:它实际上显示正在使用的显式文件,而不是
/tmp
下的丑陋临时文件,因此很容易确切地知道发生了什么,其中包括预处理/编译/汇编步骤:在 Ubuntu 22.10 amd64、GCC 8.3.0 中测试。
Visual Studio Code 鼠标悬停宏展开
将鼠标悬停在宏上会自动展开它们,它往往工作得很好!不确定是否需要正确的跨文件引用,因为我通常使用 clangd: VSCode“转到定义”不起作用
Git 源代码文件中的示例 remote.c 直接打开源目录后如下:
当我将鼠标悬停在
ALL_REV_FLAGS
上时宏:然后我还可以在悬停弹出窗口上选择文本,其中包含:
因此我们看到它既提供了其他宏方面的顶级扩展,也提供了完整的最终递归扩展。
同样在这种情况下,我们看到它跨文件工作,因为在这种情况下,定义来自文件 修订版.h。
-save-temps
The big advantage of this option over
-E
is that it is very easy to add it to any build script, without interfering much in the build itself:main.c
and now, besides the normal output
main.o
, the current working directory also contains the following files:main.i
is a contains the desired preprossessed file:main.s
is a bonus, and contains the desired generated assembly:-save-temps=obj
If you want to do it for a large number of files, consider using instead:
which saves the intermediate files to the same directory as the
-o
object output instead of the current working directory, thus avoiding potential basename conflicts.For example:
leads to the creation of files:
Clearly an Apple plot to take over the world.
-save-temps -v
Another cool thing about this option is if you add
-v
:it actually shows the explicit files being used instead of ugly temporaries under
/tmp
, so it is easy to know exactly what is going on, which includes the preprocessing / compilation / assembly steps:Tested in Ubuntu 22.10 amd64, GCC 8.3.0.
Visual Studio Code mouse hover macro expansion
Hovering over macros automatically expands them, it tends to work very well! Not sure if proper cross file referencing is needed or not, for that I normally use clangd: VSCode "go to definition" not working
Example from the Git source code file remote.c on vscode 1.87.1, C/C++ extension v1.19.6, Ubuntu 23.10 after opening the source directory directly as:
as I hover over the
ALL_REV_FLAGS
macro:I can then also select text on the hover popup, which contains:
So we see that it gives both the toplevel expansion in terms of other macros, as well as the full final recursive expansion.
Also in this case we see that it worked across files, as in this case the definition comes from file revision.h.
如果使用 Jetbrains 的 CLion,您可以使用“clangd:预处理当前 TU”操作
,因此点击
shift
shift
并开始输入 clangd...最佳将其分配给快捷方式,以便在首选项 -> 键映射中更简单地重用:
向 marcosbento
PS:TU 表示“翻译单元”(请参见此处 LLVM 翻译单元)
If using CLion by Jetbrains, you can use the action "clangd: Preprocess current TU"
So hit
shift
shift
and start typing clangd...Best assign it to a shortcut for simpler reuse in preferences->keymap:
Shout out to marcosbento
PS: TU means 'translation unit' (see here LLVM translation unit)
您可以查看此处描述的我的脚本:
http:// mosermichael.github.io/cstuff/all/projects/2011/09/16/preprocessor.html
它将预处理器输出格式化为(希望)可读的 html 文档:由于预处理器而不同的行被标记在文件。
You can check out my script described here:
http://mosermichael.github.io/cstuff/all/projects/2011/09/16/preprocessor.html
It formats the preprocessor output into a (hopefully) readable html document: lines that are different due to preprocessor are marked in the file.