Kann gcc nach der Vorverarbeitung C-Code ausgeben?

104

Ich verwende eine Open-Source-Bibliothek, die anscheinend viele Vorverarbeitungsanweisungen enthält, um viele andere Sprachen als C zu unterstützen. Damit ich untersuchen kann, was die Bibliothek tut, möchte ich den C-Code sehen, den ich nach der Vorverarbeitung kompiliere eher wie das, was ich schreiben würde.

Kann gcc (oder ein anderes unter Linux allgemein verfügbares Tool) diese Bibliothek lesen, aber C-Code ausgeben, bei dem die Vorverarbeitung in irgendetwas konvertiert wurde und der auch von einem Menschen gelesen werden kann?

LGTrader
quelle
Der vorverarbeitete Code hat keine Präprozessor-Direktiven mehr, aber ich bin mir ziemlich sicher, dass er viel weniger lesbar sein wird als vor der Vorverarbeitung ...
Alex W
2
@AlexW - Das hängt ganz davon ab, wie schrecklich die Leute, die den Code schreiben, den Präprozessor missbraucht haben.
Gefälschter Name
1
Bitte ändern Sie Ihre akzeptierte Antwort hier. gcc -Eist nützlicher, als die Zeile neu schreiben zu müssen, damit sie funktioniert cpp.
Grau

Antworten:

193

Ja. Übergeben Sie gcc die -EOption. Dadurch wird vorverarbeiteter Quellcode ausgegeben.

Mipadi
quelle
12
Wenn Ihre Compiler-Befehle bereits einen Parameter wie diesen haben -o something.o, möchten Sie diesen möglicherweise auch ändern -o something.i. Andernfalls befindet sich die vorverarbeitete Ausgabe in der .oDatei.
Tor Klingberg
@TorKlingberg Kann ich dies für mehrere Dateien gleichzeitig tun?
user2808264
@ user2808264gcc -E file1.c file2.c ...
Matthieu
68

cpp ist der Präprozessor.

Führen Sie cpp filename.cdiese Option aus, um den vorverarbeiteten Code auszugeben, oder leiten Sie ihn besser in eine Datei mit um cpp filename.c > filename.preprocessed.

tpdi
quelle
2
Ich denke, dies ist die beste Antwort, weil es cpp direkt demonstriert. Linux-Systeme (zumindest Manjaro) scheinen standardmäßig auch -E zu haben. Ich erhalte die gleichen Ergebnisse mit diesem Befehl. diffzeigt keinen Unterschied in den Dateien. Dies scheint auch eine nützliche Möglichkeit zu sein, den Code vorab zu verarbeiten und nach Fehlern in Ihren Makros zu suchen. Tolle Frage und eine tolle Antwort (IALCTHW).
Lee8oi
17

Ich verwende gcc als Präprozessor (für HTML-Dateien). Es macht genau das, was Sie wollen. Es erweitert die Direktiven "# -" und gibt dann eine lesbare Datei aus. (Keiner der anderen C / HTML-Präprozessoren, die ich versucht habe, verkettet Zeilen, verschluckt Sonderzeichen usw.) Vorausgesetzt, Sie haben gcc installiert, lautet die Befehlszeile:

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

(Muss nicht 'cpp' sein.) Eine ausgezeichnete Beschreibung dieser Verwendung finden Sie unter http://www.cs.tut.fi/~jkorpela/html/cpre.html .

Das "-traditional-cpp" behält Leerzeichen und Tabulatoren bei.

Jack Ritter
quelle
Vielen Dank, dies ist sehr hilfreich, um Python cffi cdef zu generieren!
Amirouche
13

-save-temps

Dies ist eine weitere gute Option:

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

Haupt c

#define INC 1

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

und jetzt main.oenthält das aktuelle Arbeitsverzeichnis neben der normalen Ausgabe auch die folgenden Dateien:

  • main.i ist die gewünschte vorbesessene Datei, die Folgendes enthält:

    # 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 ist ein Bonus :-) und enthält die generierte Baugruppe:

        .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

Wenn Sie dies für eine große Anzahl von Dateien tun möchten, sollten Sie stattdessen Folgendes verwenden:

 -save-temps=obj

Dadurch werden die Zwischendateien im selben Verzeichnis wie die -oObjektausgabe anstelle des aktuellen Arbeitsverzeichnisses gespeichert , wodurch potenzielle Konflikte mit Basisnamen vermieden werden.

Der Vorteil dieser Option gegenüber -Eist, dass es einfach ist, sie zu jedem Build-Skript hinzuzufügen, ohne den Build selbst stark zu beeinträchtigen.

Eine weitere coole Sache an dieser Option ist, wenn Sie hinzufügen -v:

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

Es zeigt tatsächlich die expliziten Dateien, die anstelle von hässlichen temporären Dateien verwendet werden /tmp, so dass es einfach ist, genau zu wissen, was gerade passiert, einschließlich der Schritte Vorverarbeitung / Kompilierung / Assemblierung:

/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

Getestet in Ubuntu 19.04 amd64, GCC 8.3.0.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
1
Viel eleganter als -E, da ich CFLAGS nur -save-temps hinzufügen kann, ohne das Gesamtverhalten des Build-Skripts zu ändern. Danke dir!
EvertW
Dies ist in der Tat sehr nützlich und -E ist sehr praktisch für einzelne Dateien.
Subin Sebastian
9

Lauf:

gcc -E <file>.c

oder

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

Angenommen, wir haben eine Datei als Message.cpp oder eine .c-Datei

Schritte 1: Vorverarbeitung (Argument -E)

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

Die generierte P1-Datei enthält erweiterte Makros und den Inhalt der Header-Datei. Kommentare werden entfernt.

Schritt 2: Übersetzen Sie die vorverarbeitete Datei in die Assembly (Argument -S). Diese Aufgabe erledigt der Compiler

g ++ -S. \ Message.cpp

Ein Assembler (ASM) wird generiert (Message.s). Es hat den gesamten Assembler-Code.

Schritt 3: Übersetzen Sie den Assemblycode in den Objektcode. Hinweis: Message.s wurde in Schritt 2 generiert. g ++ -c. \ Message.s

Eine Objektdatei mit dem Namen Message.o wird generiert. Es ist die binäre Form.

Schritt 4: Verknüpfen der Objektdatei. Diese Aufgabe erledigt der Linker

g ++. \ Message.o -o MessageApp

Hier wird eine exe-Datei MessageApp.exe generiert.

#include <iostream>
using namespace std;

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