Gcc può generare codice C dopo la pre-elaborazione?


105

Sto usando una libreria open source che sembra avere molte direttive di pre-elaborazione per supportare molti linguaggi diversi da C.Per poter studiare cosa sta facendo la libreria mi piacerebbe vedere il codice C che sto compilando dopo la pre-elaborazione , più simile a quello che scriverei.

Può gcc (o qualsiasi altro strumento comunemente disponibile in Linux) leggere questa libreria ma generare codice C che ha la preelaborazione convertita in qualsiasi cosa ed è anche leggibile da un essere umano?


Il codice preelaborato non avrà più direttive per il preprocessore ma sono abbastanza sicuro che sarà molto meno leggibile rispetto a prima di essere preelaborato ...
Alex W

2
@AlexW - Dipende interamente da quanto orribilmente le persone che scrivono il codice hanno abusato del preprocessore.
Fake Name

1
Si prega di considerare di modificare la risposta accettata qui. gcc -Eè più utile che dover riscrivere la riga per farlo funzionare cpp.
Gray

Risposte:


194

Sì. Passa a gcc l' -Eopzione. Questo produrrà codice sorgente preelaborato.


12
Se i comandi del tuo compilatore hanno già un parametro come -o something.opotresti cambiarlo anche in -o something.i. Altrimenti l'output preelaborato sarà nel .ofile.
Tor Klingberg

@TorKlingberg Posso farlo per più file alla volta?
user2808264

@ user2808264gcc -E file1.c file2.c ...
Matthieu

68

cpp è il preprocessore.

Esegui cpp filename.cper produrre il codice preelaborato o, meglio, reindirizzalo a un file con estensione cpp filename.c > filename.preprocessed.


2
Penso che questa sia la risposta migliore perché dimostra direttamente cpp. Anche i sistemi Linux (almeno Manjaro) sembrano avere -E per impostazione predefinita. In entrambi i casi ottengo gli stessi risultati da questo comando. diffnon rileva alcuna differenza nei file. Questo sembra anche un modo utile per preelaborare il codice alla ricerca di errori nelle macro. Ottima domanda e un'ottima risposta (IALCTHW).
lee8oi

17

Sto usando gcc come preprocessore (per i file html). Fa proprio quello che vuoi. Espande le direttive "# -", quindi genera un file leggibile. (NESSUNO degli altri preprocessori C / HTML che ho provato lo fa: concatenano linee, soffocano i caratteri speciali, ecc.) Supponendo che tu abbia gcc installato, la riga di comando è:

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

(Non deve essere "cpp".) C'è un'eccellente descrizione di questo utilizzo su http://www.cs.tut.fi/~jkorpela/html/cpre.html .

"-Traditional-cpp" conserva spazi e tabulazioni.


Molte grazie, questo è molto utile per generare python cffi cdef!
amirouche

13

-save-temps

Questa è un'altra buona opzione da tenere a mente:

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

main.c

#define INC 1

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

e ora, oltre al normale output main.o, la directory di lavoro corrente contiene anche i seguenti file:

  • main.i è il file pre-posseduto desiderato contenente:

    # 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 è un bonus :-) e contiene l'assembly generato:

        .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
    

Se vuoi farlo per un gran numero di file, considera l'utilizzo invece:

 -save-temps=obj

che salva i file intermedi nella stessa directory -odell'output dell'oggetto invece che nella directory di lavoro corrente, evitando così potenziali conflitti di nomi di base.

Il vantaggio di questa opzione -Eè che è facile aggiungerla a qualsiasi script di build, senza interferire molto con la build stessa.

Un'altra cosa interessante di questa opzione è se aggiungi -v:

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

in realtà mostra i file espliciti utilizzati al posto dei brutti temporanei sotto /tmp, quindi è facile sapere esattamente cosa sta succedendo, che include i passaggi di pre-elaborazione / compilazione / assemblaggio:

/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

Testato in Ubuntu 19.04 amd64, GCC 8.3.0.


1
Molto più elegante di -E perché posso semplicemente aggiungere -save-temps a CFLAGS senza modificare il comportamento generale dello script di compilazione. Grazie!
EvertW

Questo è davvero molto utile e -E è molto conveniente per i singoli file.
Subin Sebastian


1

Supponiamo di avere un file come Message.cpp o un file .c

Passaggi 1: pre - elaborazione (argomento -E)

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

Il file P1 generato ha macro espanse e il contenuto del file di intestazione e i commenti vengono rimossi.

Passaggio 2: tradurre il file preelaborato in assembly (argomento -S). Questa attività viene eseguita dal compilatore

g ++ -S. \ Message.cpp

Viene generato un assemblatore (ASM) (Message.s). Ha tutto il codice di assemblaggio.

Passaggio 3: tradurre il codice assembly in codice oggetto. Nota: Message.s è stato generato nel passaggio 2. g ++ -c. \ Message.s

Viene generato un file oggetto con il nome Message.o. È la forma binaria.

Passaggio 4: collegamento del file oggetto. Questa attività viene eseguita dal linker

g ++. \ Message.o -o MessageApp

Un file exe MessageApp.exe viene generato qui.

#include <iostream>
using namespace std;

 //This a sample program
  int main()
{
cout << "Hello" << endl;
 cout << PQR(P,K) ;
getchar();
return 0;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.