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.
gcc -E file.c
or
g++ -E file.cpp
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.
-x c
if the file you are processing has not a standard c extension
You can also call the C Preprocessor directly.
cpp infile outfile
Check out man cpp
for more info.
cc -E
. Also, I use -P
to disable line markets too (works with cc
as well).
For GCC,
gcc -E -dM file.c
or
g++ -E -dM file.cpp
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.
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
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:
gcc -save-temps -c -o main.o main.c
main.c
#define INC 1
int myfunc(int i) {
return i + INC;
}
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:
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "main.c"
int myfunc(int i) {
return i + 1;
}
main.s
is a bonus, and contains the desired generated assembly:
.file "main.c"
.text
.globl myfunc
.type myfunc, @function
myfunc:
.LFB0:
.cfi_startproc
pushq %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
addl $1, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size myfunc, .-myfunc
.ident "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0"
.section .note.GNU-stack,"",@progbits
-save-temps=obj
If you want to do it for a large number of files, consider using instead:
-save-temps=obj
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:
gcc -save-temps -c -o out/subdir/main.o subdir/main.c
leads to the creation of files:
out/subdir/main.i
out/subdir/main.o
out/subdir/main.s
Clearly an Apple plot to take over the world.
-save-temps -v
Another cool thing about this option is if you add -v
:
gcc -save-temps -c -o main.o -v main.c
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:
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu main.c -mtune=generic -march=x86-64 -fpch-preprocess -fstack-protector-strong -Wformat -Wformat-security -o main.i
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -fpreprocessed main.i -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase-strip main.o -version -fstack-protector-strong -Wformat -Wformat-security -o main.s
as -v --64 -o main.o main.s
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:
git clone https://github.com/git/git
cd git
git checkout e09f1254c54329773904fe25d7c545a1fb4fa920
code .
as I hover over the ALL_REV_FLAGS
macro:
I can then also select text on the hover popup, which contains:
#define ALL_REV_FLAGS (((1u<<11)-1) | NOT_USER_GIVEN | TRACK_LINEAR | PULL_MERGE)
Expands to:
(((1u<<11)-1) | (1u<<25) | (1u<<26) | (1u<<15))
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.
-save-temps=obj
method is the best, too. I wrote about it in my answer here: Where do we use .i files and how do we generate them?.
Dec 6, 2023 at 21:25
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)
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.
.i
files and how do we generate them?