Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can gcc output C code after preprocessing?

People also ask

What does the GCC preprocessor do?

The preprocessor outputs one make rule containing the object file name for that source file, a colon, and the names of all the included files, including those coming from -include or -imacros command-line options.

What is the GCC option that runs only the preprocessor?

The -E option causes gcc to run the preprocessor, display the expanded output, and then exit without compiling the resulting source code.

What is the output of preprocessor?

In computer science, a preprocessor (or precompiler) is a program that processes its input data to produce output that is used as input to another program. The output is said to be a preprocessed form of the input data, which is often used by some subsequent programs like compilers.

What happens in preprocessing in C?

The C Preprocessor is not a part of the compiler, but is a separate step in the compilation process. In simple terms, a C Preprocessor is just a text substitution tool and it instructs the compiler to do required pre-processing before the actual compilation.


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


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.


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.


-save-temps

This is another good option to have in mind:

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
    

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.

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.

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


Run:

gcc -E <file>.c

or

g++ -E <file>.cpp

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