¿Puede gcc generar código C después del preprocesamiento?
-
29-10-2019 - |
Pregunta
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 estoycompilando después del preprocesamiento, más como lo que yo escribiría.
¿Puede gcc (o cualquier otra herramienta comúnmente disponible en Linux) leer esta biblioteca pero generar código C que tiene el preprocesamiento convertido a lo que sea y que también sea legible por un humano?
Solución
Sí.Pase gcc la opción -E
.Esto generará código fuente preprocesado.
Otros consejos
cpp
es el preprocesador.
Ejecute cpp filename.c
para generar el código preprocesado, o mejor, redirigirlo a un archivo con
cpp filename.c > filename.preprocessed
.
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 -x c -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.
Ejecutar:
gcc -E <file>.c
o
g++ -E <file>.cpp
<×-save-temps
Esta es otra buena opción a tener en cuenta:
gcc -save-temps -c -o main.o main.c
main.c
#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 una ventaja :-) 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 salida del objeto -o
en lugar del directorio de trabajo actual, evitando así posibles conflictos de nombres de base.
La ventaja de esta opción sobre -E
es que es fácil de agregar 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 feos temporales en /tmp
, por lo que es fácil saber exactamente qué está pasando, 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.
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 y los comentarios del archivo de encabezado están eliminados.
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: traduzca 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 vinculador
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;
}