¿Puede gcc generar código C después del preprocesamiento?

104

Estoy usando una biblioteca de código abierto que parece tener muchas directivas de preprocesamiento para admitir muchos lenguajes además de C. Para poder estudiar lo que está haciendo la biblioteca, me gustaría ver el código C que estoy compilando después del preprocesamiento. , más como lo que escribiría.

¿Puede gcc (o cualquier otra herramienta comúnmente disponible en Linux) leer esta biblioteca pero generar un código C que tiene el preprocesamiento convertido a lo que sea y que también sea legible por un humano?

LGTrader
fuente
El código preprocesado ya no tendrá directivas de preprocesador, pero estoy bastante seguro de que será mucho menos legible que antes de ser preprocesado ...
Alex W
2
@AlexW - Eso depende completamente de cuán horriblemente las personas que escribieron el código abusaron del preprocesador.
Nombre falso
1
Considere cambiar su respuesta aceptada aquí. gcc -Ees más útil que tener que reescribir la línea para que funcione cpp.
Grey

Respuestas:

193

Si. Pase gcc la -Eopción. Esto generará código fuente preprocesado.

mipadi
fuente
12
Si los comandos de su compilador ya tienen un parámetro como, -o something.oes posible que también desee cambiarlo -o something.i. De lo contrario, la salida preprocesada estará en el .oarchivo.
Tor Klingberg
@TorKlingberg ¿Puedo hacer esto para varios archivos a la vez?
user2808264
@ user2808264gcc -E file1.c file2.c ...
Matthieu
68

cpp es el preprocesador.

Ejecutar cpp filename.cpara generar el código preprocesado, o mejor, redirigirlo a un archivo con cpp filename.c > filename.preprocessed.

tpdi
fuente
2
Creo que esta es la mejor respuesta porque demuestra cpp directamente. Los sistemas Linux (al menos Manjaro) también parecen tener -E por defecto. Obtengo los mismos resultados de este comando de cualquier manera. diffno muestra ninguna diferencia en los archivos. Esta también parece una forma útil de preprocesar el código en busca de errores en sus macros. Gran pregunta y gran respuesta (IALCTHW).
lee8oi
17

Estoy usando gcc como preprocesador (para archivos html). Hace exactamente lo que quieres. Expande las directivas "# -" y luego genera un archivo legible. (NINGUNO de los otros preprocesadores C / HTML que he intentado hacer esto: concatenan líneas, se ahogan con caracteres especiales, etc.) Suponiendo que tiene instalado gcc, la línea de comando es:

gcc -E -xc -P -C -traditional-cpp code_before.cpp> code_after.cpp

(No tiene que ser 'cpp'). Hay una excelente descripción de este uso en http://www.cs.tut.fi/~jkorpela/html/cpre.html .

El "-traditional-cpp" conserva los espacios en blanco y las pestañas.

Jack Ritter
fuente
¡Muchas gracias, esto es muy útil para generar python cffi cdef!
amirouche
13

-save-temps

Esta es otra buena opción a tener en cuenta:

gcc -save-temps -c -o main.o main.c

C Principal

#define INC 1

int myfunc(int i) {
    return i + INC;
}

y ahora, además de la salida normal main.o, el directorio de trabajo actual también contiene los siguientes archivos:

  • main.i es el archivo predilecto deseado que contiene:

    # 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 es un bono :-) y contiene el ensamblado generado:

        .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
    

Si desea hacerlo para una gran cantidad de archivos, considere usar en su lugar:

 -save-temps=obj

que guarda los archivos intermedios en el mismo directorio que la -osalida del objeto en lugar del directorio de trabajo actual, evitando así posibles conflictos de nombres de base.

La ventaja de esta opción -Ees que es fácil agregarla a cualquier script de compilación, sin interferir mucho en la compilación en sí.

Otra cosa interesante de esta opción es si agrega -v:

gcc -save-temps -c -o main.o -v main.c

en realidad, muestra los archivos explícitos que se utilizan en lugar de los feos temporales /tmp, por lo que es fácil saber exactamente qué está sucediendo, lo que incluye los pasos de preprocesamiento / compilación / ensamblaje:

/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

Probado en Ubuntu 19.04 amd64, GCC 8.3.0.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
1
Mucho más elegante que -E porque puedo agregar -save-temps a CFLAGS sin cambiar el comportamiento general del script de compilación. ¡Gracias!
EvertW
De hecho, esto es muy útil y -E es muy conveniente para archivos individuales.
Subin Sebastian
9

Correr:

gcc -E <file>.c

o

g++ -E <file>.cpp
Andrii Pyvovar
fuente
1

Supongamos que tenemos un archivo como Message.cpp o un archivo .c

Pasos 1: preprocesamiento (argumento -E)

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

El archivo P1 generado tiene macros expandidas y el contenido del archivo de encabezado y los comentarios se eliminan.

Paso 2: Traducir el archivo preprocesado a ensamblado (Argumento -S). Esta tarea la realiza el compilador

g ++ -S. \ Message.cpp

Se genera un ensamblador (ASM) (Message.s). Tiene todo el código ensamblador.

Paso 3: Traducir el código ensamblador al código del objeto. Nota: Message.s se generó en Step2. g ++ -c. \ Message.s

Se genera un archivo de objeto con el nombre Message.o. Es la forma binaria.

Paso 4: vincular el archivo de objeto. Esta tarea la realiza el enlazador

g ++. \ Message.o -o MessageApp

Aquí se genera un archivo exe MessageApp.exe.

#include <iostream>
using namespace std;

 //This a sample program
  int main()
{
cout << "Hello" << endl;
 cout << PQR(P,K) ;
getchar();
return 0;
}
Pranav Kumar
fuente