Gcc peut-il générer du code C après le prétraitement?

105

J'utilise une bibliothèque open source qui semble avoir beaucoup de directives de prétraitement pour prendre en charge de nombreux langages autres que C.Pour que je puisse étudier ce que fait la bibliothèque, j'aimerais voir le code C que je compile après le prétraitement , plus comme ce que j'écrirais.

Est-ce que gcc (ou tout autre outil couramment disponible sous Linux) peut lire cette bibliothèque mais générer du code C dont le prétraitement est converti en n'importe quoi et qui est également lisible par un humain?

LGTrader
la source
Le code pré-traité n'aura plus de directives de préprocesseur mais je suis assez sûr qu'il sera beaucoup moins lisible qu'avant d'être prétraité ...
Alex W
2
@AlexW - Cela dépend entièrement de la façon dont les personnes qui écrivent le code ont abusé du préprocesseur.
Fake Name
1
Veuillez envisager de modifier votre réponse acceptée ici. gcc -Eest plus utile que d'avoir à réécrire la ligne pour la faire fonctionner cpp.
Gray

Réponses:

194

Oui. Passez l' -Eoption gcc . Cela produira un code source prétraité.

mipadi
la source
12
Si les commandes de votre compilateur ont déjà un paramètre comme -o something.ovous pouvez également le changer en -o something.i. Sinon, la sortie prétraitée sera dans le .ofichier.
Tor Klingberg
@TorKlingberg Puis-je faire cela pour plusieurs fichiers à la fois?
user2808264
@ user2808264gcc -E file1.c file2.c ...
Matthieu
68

cpp est le préprocesseur.

Exécutez cpp filename.cpour sortir le code prétraité, ou mieux, redirigez-le vers un fichier avec cpp filename.c > filename.preprocessed.

tpdi
la source
2
Je pense que c'est la meilleure réponse car elle démontre directement cpp. Les systèmes Linux (du moins Manjaro) semblent également avoir -E par défaut. J'obtiens les mêmes résultats de cette commande de toute façon. diffne révèle aucune différence dans les fichiers. Cela ressemble également à un moyen utile de prétraiter le code à la recherche d'erreurs dans vos macros. Excellente question et excellente réponse (IALCTHW).
lee8oi
17

J'utilise gcc comme préprocesseur (pour les fichiers html.) Il fait exactement ce que vous voulez. Il développe les directives "# -", puis génère un fichier lisible. (AUCUN des autres préprocesseurs C / HTML que j'ai essayés ne le font - ils concaténent des lignes, s'étouffent avec des caractères spéciaux, etc.) En supposant que gcc soit installé, la ligne de commande est:

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

(N'a pas besoin d'être «cpp».) Il y a une excellente description de cette utilisation à http://www.cs.tut.fi/~jkorpela/html/cpre.html .

Le "-traditional-cpp" préserve les espaces et les tabulations.

Jack Ritter
la source
Merci beaucoup, c'est très utile pour générer python cffi cdef!
amirouche
13

-save-temps

Voici une autre bonne option à garder à l'esprit:

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

principal c

#define INC 1

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

et maintenant, en plus de la sortie normale main.o, le répertoire de travail actuel contient également les fichiers suivants:

  • main.i est le fichier préposés souhaité contenant:

    # 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 est un bonus :-) et contient l'assemblage généré:

        .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 vous souhaitez le faire pour un grand nombre de fichiers, envisagez d'utiliser à la place:

 -save-temps=obj

qui enregistre les fichiers intermédiaires dans le même répertoire que la -osortie de l' objet au lieu du répertoire de travail courant, évitant ainsi les conflits de nom de base potentiels.

L'avantage de cette option -Eest qu'il est facile de l'ajouter à n'importe quel script de construction, sans trop interférer dans la construction elle-même.

Une autre chose intéressante à propos de cette option est si vous ajoutez -v:

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

il montre en fait les fichiers explicites utilisés au lieu des horribles temporaires sous /tmp, il est donc facile de savoir exactement ce qui se passe, ce qui inclut les étapes de prétraitement / compilation / assemblage:

/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

Testé dans Ubuntu 19.04 amd64, GCC 8.3.0.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
1
Beaucoup plus élégant que -E car je peux simplement ajouter -save-temps à CFLAGS sans changer le comportement général du script de construction. Je vous remercie!
EvertW
C'est en effet très utile, et -E est très pratique pour les fichiers uniques.
Subin Sebastian
9

Courir:

gcc -E <file>.c

ou

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

Supposons que nous ayons un fichier comme Message.cpp ou un fichier .c

Étapes 1: prétraitement (argument -E)

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

Le fichier P1 généré a des macros développées et le contenu du fichier d'en-tête et les commentaires sont supprimés.

Étape 2: Traduire le fichier prétraité en assembly (Argument -S). Cette tâche est effectuée par le compilateur

g ++ -S. \ Message.cpp

Un assembleur (ASM) est généré (Message.s). Il a tout le code d'assemblage.

Étape 3: Traduire le code d'assembly en code objet. Remarque: Message.s a été généré à l'étape 2. g ++ -c. \ Message.s

Un fichier objet avec le nom Message.o est généré. C'est la forme binaire.

Étape 4: Lier le fichier objet. Cette tâche est effectuée par l'éditeur de liens

g ++. \ Message.o -o MessageApp

Un fichier exe MessageApp.exe est généré ici.

#include <iostream>
using namespace std;

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