Can gcc output C code after preprocessing?

149.8k Views Asked by At

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?

6

There are 6 best solutions below

4
On BEST ANSWER

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

2
On

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.

5
On

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

0
On

Run:

gcc -E <file>.c

or

g++ -E <file>.cpp
2
On

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.

1
On

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;
}