webentwicklung-frage-antwort-db.com.de

Kann gcc C-Code nach der Vorverarbeitung ausgeben?

Ich verwende eine Open-Source-Bibliothek, die viele Vorverarbeitungs-Direktiven zu haben scheint, 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 was ich schreiben würde.

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

85
LGTrader

Ja. Gib gcc das -E Möglichkeit. Dadurch wird vorverarbeiteter Quellcode ausgegeben.

177
mipadi

cpp ist der Präprozessor.

Führen Sie cpp filename.c Aus, um den vorverarbeiteten Code auszugeben, oder leiten Sie ihn besser mit cpp filename.c > filename.preprocessed In eine Datei um.

62
tpdi

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

gcc -E -x c -P -C -traditional-cpp code_before.cpp> code_after.cpp

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

Das "-traditional-cpp" bewahrt Leerzeichen und Tabulatoren.

13
Jack Ritter

Lauf:

gcc -E <file>.c

oder

g++ -E <file>.cpp
9
Andrii Pyvovar

-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 enthält das aktuelle Arbeitsverzeichnis neben der normalen Ausgabe main.o auch die folgenden Dateien:

  • main.i Ist die gewünschte vorbesessene Datei mit:

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

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 gespeichert wie die Ausgabe des Objekts -o anstelle des aktuellen Arbeitsverzeichnisses, wodurch mögliche Konflikte mit Basisnamen vermieden werden.

Der Vorteil dieser Option gegenüber -E Ist, dass sie einfach zu jedem Build-Skript hinzugefügt werden kann, ohne dass der Build selbst stark beeinträchtigt wird.

Eine weitere coole Sache bei dieser Option ist, wenn Sie -v Hinzufügen:

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

es zeigt tatsächlich die expliziten Dateien, die unter /tmp anstelle von hässlichen temporären Dateien verwendet werden, so dass es einfach ist, genau zu wissen, was vor sich geht, 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 unter Ubuntu 19.04 AMD64, GCC 8.3.0.

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 Header-Dateien. Kommentare werden entfernt.

Schritt 2: Vorverarbeitete Datei in Assembly übersetzen (Argument -S). Diese Aufgabe übernimmt der Compiler

g ++ -S.\Message.cpp

Ein Assembler (ASM) wird generiert (Message.s). Es hat alle Assembly-Code.

Schritt 3: Baugruppencode in Objektcode übersetzen. 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 übernimmt der Linker

g ++.\Message.o -o MessageApp

Hier wird eine exe-Datei MessageApp.exe erzeugt.

#include <iostream>
using namespace std;

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