web-dev-qa-db-fra.com

Est-ce que gcc peut sortir du code C après le prétraitement?

J'utilise une bibliothèque open source qui semble contenir de nombreuses directives de prétraitement pour prendre en charge de nombreux langages autres que le langage C. Pour pouvoir é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.

Gcc (ou tout autre outil communément disponible sous Linux) peut-il lire cette bibliothèque mais générer du code C dont le prétraitement est converti en quelque chose de ce type et lisible par un humain?

85
LGTrader

Oui. Passer gcc le -E option. Cela produira du code source prétraité.

177
mipadi

cpp est le préprocesseur.

Courir cpp filename.c pour sortir le code prétraité, ou mieux, le rediriger vers un fichier avec cpp filename.c > filename.preprocessed.

62
tpdi

J'utilise gcc en tant que 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 - ils concaténent des lignes, étouffent des caractères spéciaux, etc.) En supposant que gcc soit installé, la ligne de commande est la suivante:

gcc -E -x c -P -C -traditional-cpp code_avant.cpp> code_après.cpp

(Ne doit pas nécessairement être 'cpp'.) Il existe une excellente description de cet usage à l'adresse http://www.cs.tut.fi/~jkorpela/html/cpre.html .

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

13
Jack Ritter

Courir:

gcc -E <file>.c

ou

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

-save-temps

C’est 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, outre la sortie normale main.o, le répertoire de travail actuel contient également les fichiers suivants:

  • main.i est le fichier préfabriqué 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'assembly 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, utilisez plutôt:

 -save-temps=obj

qui enregistre les fichiers intermédiaires dans le même répertoire que le -o sortie de l'objet à la place du répertoire de travail en cours, évitant ainsi des conflits potentiels de noms de bases.

L'avantage de cette option sur -E est 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 à la place de laids temporaries 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é sous Ubuntu 19.04 AMD64, GCC 8.3.0.

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

Etapes 1: Prétraitement (Argument -E)

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

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

Étape 2: Convertissez 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 de l'Assemblée.

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

Un fichier Object portant 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;
}
1
Pranav Kumar