92

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.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985

7 Answers7

120
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.

Faisal Feroz
  • 12,458
  • 4
  • 40
  • 51
23

You can also call the C Preprocessor directly.

cpp infile outfile

Check out man cpp for more info.

rdas
  • 20,604
  • 6
  • 33
  • 46
  • 1
    Nice! I prefer this one over `cc -E`. Also, I use `-P` to disable line markets too (works with `cc` as well). – mtmk Feb 21 '20 at 18:13
12

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.

5

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.

Bart van Ingen Schenau
  • 15,488
  • 4
  • 32
  • 41
3

If using CLion by Jetbrains, you can use the action "clangd: Preprocess current TU"

So hit shift shift and start typing clangd...

action popup

Best assign it to a shortcut for simpler reuse in preferences->keymap:

enter image description here

Shout out to marcosbento

PS: TU means 'translation unit' (see here LLVM translation unit)

Rhubarb
  • 34,705
  • 2
  • 49
  • 38
0

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.

MichaelMoser
  • 3,172
  • 1
  • 26
  • 26
0

-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.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985