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?
Ja. Gib gcc das -E
Möglichkeit. Dadurch wird vorverarbeiteter Quellcode ausgegeben.
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.
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.
Lauf:
gcc -E <file>.c
oder
g++ -E <file>.cpp
-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;
}