159

I'm using an open source library which seems to have lots of preprocessing directives to support many languages other than C. So that I can study what the library is doing I'd like to see the C code that I'm compiling after preprocessing, more like what I'd write.

Can gcc (or any other tool commonly available in Linux) read this library but output C code that has the preprocessing converted to whatever and is also readable by a human?

4
  • The preprocessed code wont have any preprocessor directives anymore but I am fairly sure it will be much much less readable than before being preprocessed... Commented Feb 5, 2011 at 2:58
  • 3
    @AlexW - That depends entirely on how horribly the people writing the code abused the preprocessor. Commented Sep 6, 2017 at 0:34
  • 2
    Please consider changing your accepted answer here. gcc -E is more useful than having to rewrite the line to make it work with cpp. Commented Mar 27, 2018 at 21:31
  • 2
    Ciro provided a very good gcc -save-temps I suggest to take a look. Commented Dec 8, 2021 at 3:37

6 Answers 6

262

Yes. Pass gcc the -E option. This will output preprocessed source code.

Sign up to request clarification or add additional context in comments.

4 Comments

If your compiler commands already has a parameter like -o something.o you may also want to change it to -o something.i. Otherwise the preprocessed output will be in the .o file.
@TorKlingberg Can I do this for multiple files at a time?
@user2808264 gcc -E file1.c file2.c ...
Is there an option for the preprocessor to expand only macroses like #define SIZE 1000 or #ifdef Something #endif but not #include <other_file.h> I want to see a preprocessed file but without external functions imported into a single file.
82

cpp is the preprocessor.

Run cpp filename.c to output the preprocessed code, or better, redirect it to a file with cpp filename.c > filename.preprocessed.

2 Comments

I think this is the best answer because it demonstrates cpp directly. Linux systems (at least Manjaro) seem to have -E by default too. I get the same results from this command either way. diff turns up no difference in the files. This is also looks like a useful way to preprocess the code looking for errors in your macros. Great question and a great answer (IALCTHW).
@lee8oi I was curious what IALCTHW meant but my attempt to web search for it only resulted in this page as a search result. What does that acronym mean? I am quite curious.
43

-save-temps

The advantage of this option over -E is that it is 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 the desired prepossessed file containing:

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

Docs: https://gcc.gnu.org/onlinedocs/gcc/Developer-Options.html#index-save-temps

-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 19.04 (Disco Dingo) amd64, GCC 8.3.0.

CMake predefined targets

CMake automatically provides a targets for the preprocessed file:

make help 

shows us that we can do:

make main.i 

and that target runs:

Preprocessing C source to CMakeFiles/main.dir/main.c.i /usr/bin/cc -E /home/ciro/bak/hello/main.c > CMakeFiles/main.dir/main.c.i 

so the file can be seen at CMakeFiles/main.dir/main.c.i

Tested on cmake 3.16.1.

3 Comments

Much more elegant than -E because I can just add -save-temps to CFLAGS without changing the overall behaviour of the build script. Thank you!
This is indeed very useful, and -E is very convenient for single files.
And for make, one can do: make CFLAGS+="--save-temps"
23

I'm using gcc as a preprocessor (for html files.) It does just what you want. It expands "#--" directives, then outputs a readable file. (NONE of the other C/HTML preprocessors I've tried do this- they concatenate lines, choke on special characters, etc.) Asuming you have gcc installed, the command line is:

gcc -E -x c -P -C -traditional-cpp code_before.cpp > code_after.cpp

(Doesn't have to be 'cpp'.) There's an excellent description of this usage at http://www.cs.tut.fi/~jkorpela/html/cpre.html.

The "-traditional-cpp" preserves whitespace & tabs.

2 Comments

Many thanks, this is very helpful to generate python cffi cdef!
cpre article link jkorpela.fi/html/cpre.html I am guessing this is what is filling the suggested edit queue...
12

Run:

gcc -E <file>.c 

or

g++ -E <file>.cpp 

Comments

6

Suppose we have a file as Message.cpp or a .c file

Steps 1: Preprocessing (Argument -E)

g++ -E .\Message.cpp > P1 

P1 file generated has expanded macros and header file contents and comments are stripped off.

Step 2: Translate Preprocessed file to assembly (Argument -S). This task is done by compiler

g++ -S .\Message.cpp 

An assembler (ASM) is generated (Message.s). It has all the assembly code.

Step 3: Translate assembly code to Object code. Note: Message.s was generated in Step2.

g++ -c .\Message.s 

An Object file with the name Message.o is generated. It is the binary form.

Step 4: Linking the object file. This task is done by linker

g++ .\Message.o -o MessageApp 

An exe file MessageApp.exe is generated here.

#include <iostream> using namespace std; //This a sample program int main() { cout << "Hello" << endl; cout << PQR(P,K) ; getchar(); return 0; } 

1 Comment

A little late! You can skip steps 2 and 3 -- g++/gcc recognize .i files as preprocessed source code. First, #define the PQR macro in the source file. Then: Step 1: g++ -E Message.cpp > Message.i Step 2: g++ Message.i > MessageApp

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.