O gcc pode gerar código C após o pré-processamento?

105

Estou usando uma biblioteca de código aberto que parece ter muitas diretivas de pré-processamento para suportar muitas linguagens diferentes de C. Para que eu possa estudar o que a biblioteca está fazendo, gostaria de ver o código C que estou compilando após o pré-processamento , mais parecido com o que eu escreveria.

O gcc (ou qualquer outra ferramenta comumente disponível no Linux) pode ler esta biblioteca, mas gerar o código C que tem o pré-processamento convertido para qualquer coisa e também pode ser lido por um humano?

LGTrader
fonte
O código pré-processado não terá mais diretivas de pré-processador, mas tenho quase certeza de que será muito menos legível do que antes de ser pré-processado ...
Alex W
2
@AlexW - Isso depende inteiramente de quão horrivelmente as pessoas que escreveram o código abusaram do pré-processador.
Nome falso,
1
Considere alterar sua resposta aceita aqui. gcc -Eé mais útil do que reescrever a linha para que funcione cpp.
Gray

Respostas:

194

Sim. Passe a -Eopção gcc . Isso produzirá código-fonte pré-processado.

mipadi
fonte
12
Se os comandos do seu compilador já possuem um parâmetro como, -o something.ovocê também pode alterá-lo para -o something.i. Caso contrário, a saída pré-processada estará no .oarquivo.
Tor Klingberg,
@TorKlingberg Posso fazer isso para vários arquivos de uma vez?
user2808264
@ user2808264gcc -E file1.c file2.c ...
Matthieu
68

cpp é o pré-processador.

Execute cpp filename.cpara gerar o código pré-processado ou, melhor, redirecioná-lo para um arquivo com cpp filename.c > filename.preprocessed.

tpdi
fonte
2
Acho que esta é a melhor resposta porque demonstra o cpp diretamente. Os sistemas Linux (pelo menos Manjaro) parecem ter -E por padrão também. Eu obtenho os mesmos resultados com este comando de qualquer maneira. diffAcontece nenhuma diferença nos arquivos. Essa também parece uma maneira útil de pré-processar o código à procura de erros em suas macros. Ótima pergunta e uma ótima resposta (IALCTHW).
lee8oi
17

Estou usando o gcc como pré-processador (para arquivos html). Ele faz exatamente o que você deseja. Ele expande as diretivas "# -" e produz um arquivo legível. (NONE

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

(Não precisa ser 'cpp'.) Há uma excelente descrição desse uso em http://www.cs.tut.fi/~jkorpela/html/cpre.html .

O "-traditional-cpp" preserva os espaços em branco e as guias.

Jack Ritter
fonte
Muito obrigado, isso é muito útil para gerar python cffi cdef!
amirouche
13

-save-temps

Esta é outra boa opção a se ter em mente:

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

main.c

#define INC 1

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

e agora, além da saída normal main.o, o diretório de trabalho atual também contém os seguintes arquivos:

  • main.i é o arquivo pré-possuído desejado contendo:

    # 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 é um bônus :-) e contém o conjunto gerado:

        .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

Se você quiser fazer isso para um grande número de arquivos, considere usar:

 -save-temps=obj

que salva os arquivos intermediários no mesmo diretório da -osaída do objeto em vez do diretório de trabalho atual, evitando assim possíveis conflitos de nome de base.

A vantagem dessa opção -Eé que é fácil adicioná-la a qualquer script de construção, sem interferir muito na própria construção.

Outra coisa legal sobre essa opção é se você adicionar -v:

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

na verdade, ele mostra os arquivos explícitos sendo usados ​​em vez de temporários feios sob /tmp, então é fácil saber exatamente o que está acontecendo, o que inclui as etapas de pré-processamento / compilação / montagem:

/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

Testado no Ubuntu 19.04 amd64, GCC 8.3.0.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fonte
1
Muito mais elegante do que -E porque posso apenas adicionar -save-temps a CFLAGS sem alterar o comportamento geral do script de construção. Obrigado!
EvertW
Isso é realmente muito útil e -E é muito conveniente para arquivos individuais.
Subin Sebastian
9

Corre:

gcc -E <file>.c

ou

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

Suponha que temos um arquivo como Message.cpp ou um arquivo .c

Etapas 1: pré - processamento (argumento -E)

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

O arquivo P1 gerado tem macros expandidas e o conteúdo e os comentários do arquivo de cabeçalho são removidos.

Etapa 2: Traduzir o arquivo pré-processado para o assembly (Argumento -S). Esta tarefa é feita pelo compilador

g ++ -S. \ Message.cpp

Um montador (ASM) é gerado (Message.s). Ele contém todo o código de montagem.

Etapa 3: Traduzir o código do assembly para o código do objeto. Nota: Message.s foi gerado na Etapa 2. g ++ -c. \ Message.s

Um arquivo Object com o nome Message.o é gerado. É a forma binária.

Etapa 4: Vinculando o arquivo objeto. Esta tarefa é realizada pelo vinculador

g ++. \ Message.o -o MessageApp

Um arquivo exe MessageApp.exe é gerado aqui.

#include <iostream>
using namespace std;

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