Gcc, ön işlemeden sonra C kodunu çıkarabilir mi?


105

C dışında birçok dili desteklemek için birçok ön işleme yönergesine sahip gibi görünen açık kaynaklı bir kitaplık kullanıyorum. Böylece kitaplığın ne yaptığını inceleyebilirim Ön işlemden sonra derlediğim C kodunu görmek isterim , daha çok yazdığım gibi.

Gcc (veya Linux'ta yaygın olarak bulunan başka herhangi bir araç) bu kitaplığı okuyabilir, ancak önişlemenin her şeye dönüştürüldüğü ve aynı zamanda bir insan tarafından okunabilen C kodunu çıktı olarak verebilir mi?


Önceden işlenmiş kod artık herhangi bir önişlemci yönergesine sahip olmayacak, ancak önişlemeden öncesine göre çok daha az okunabilir olacağından oldukça eminim ...
Alex W

2
@AlexW - Bu tamamen , kodu yazan kişilerin ön işlemciyi ne kadar korkunç bir şekilde kötüye kullandığına bağlı.
Sahte İsim

1
Lütfen kabul ettiğiniz cevabı buradan değiştirmeyi düşünün. gcc -Eçalışması için satırı yeniden yazmaktan daha kullanışlıdır cpp.
Grey

Yanıtlar:


194

Evet. -ESeçeneği gcc'ye iletin . Bu, önceden işlenmiş kaynak kodunu çıkaracaktır.


12
Derleyici komutlarınız zaten sizin gibi bir parametreye sahipse, -o something.oonu da değiştirmek isteyebilirsiniz -o something.i. Aksi takdirde, önceden işlenmiş çıktı .odosyada olacaktır.
Tor Klingberg

@TorKlingberg Bunu aynı anda birden fazla dosya için yapabilir miyim?
user2808264

@ user2808264gcc -E file1.c file2.c ...
Matthieu

68

cpp önişlemcidir.

cpp filename.cÖnceden işlenmiş kodun çıktısını almak için çalıştırın veya daha iyisi ile bir dosyaya yönlendirin cpp filename.c > filename.preprocessed.


2
Bunun en iyi cevap olduğunu düşünüyorum çünkü cpp'yi doğrudan gösteriyor. Linux sistemleri (en azından Manjaro) da varsayılan olarak -E'ye sahip görünüyor. Her iki şekilde de bu komuttan aynı sonuçları alıyorum. diffdosyalarda hiçbir fark ortaya çıkmaz. Bu ayrıca, makrolarınızdaki hataları arayan kodu önceden işlemenin yararlı bir yolu gibi görünüyor. Harika soru ve harika bir cevap (IALCTHW).
lee8oi

17

Önişlemci olarak gcc kullanıyorum (html dosyaları için.) Tam istediğinizi yapıyor. "# -" yönergelerini genişletir ve ardından okunabilir bir dosya çıkarır. (Bunu denediğim diğer C / HTML ön işlemcilerinden HİÇBİRİ - satırları birleştiriyorlar, özel karakterleri boğuyorlar, vb.) Gcc'nin kurulu olduğunu varsayarsak, komut satırı:

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

('Cpp' olması gerekmez.) Bu kullanımın mükemmel bir açıklaması http://www.cs.tut.fi/~jkorpela/html/cpre.html adresinde bulunmaktadır .

"-Traditional-cpp" beyaz boşlukları ve sekmeleri korur.


Çok teşekkürler, bu python cffi cdef'i oluşturmak için çok yararlıdır!
amirouche

13

-save-temps

Bu, akılda tutulması gereken başka bir iyi seçenektir:

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

main.c

#define INC 1

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

ve şimdi, normal çıktının yanı sıra, main.ogeçerli çalışma dizini aşağıdaki dosyaları da içerir:

  • main.i aşağıdakileri içeren istenen önceden sahiplenmiş dosyadır:

    # 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 bir bonus :-) ve oluşturulan derlemeyi içerir:

        .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
    

Bunu çok sayıda dosya için yapmak istiyorsanız, bunun yerine şunu kullanmayı düşünün:

 -save-temps=obj

Bu, ara dosyaları -ogeçerli çalışma dizini yerine nesne çıktısıyla aynı dizine kaydeder , böylece olası taban adı çakışmalarını önler.

Bu seçeneğin avantajı -E, yapının kendisine çok fazla müdahale etmeden onu herhangi bir yapı betiğine eklemenin kolay olmasıdır.

Bu seçenekle ilgili bir başka harika şey de şunu eklerseniz -v:

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

aslında altında çirkin geçiciler yerine kullanılan açık dosyaları gösterir /tmp, bu nedenle ön işleme / derleme / birleştirme adımlarını içeren tam olarak ne olduğunu bilmek kolaydır:

/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

Ubuntu 19.04 amd64, GCC 8.3.0'da test edilmiştir.


1
-E'den çok daha zarif çünkü derleme betiğinin genel davranışını değiştirmeden CFLAGS'ye -save-temps ekleyebilirim. Teşekkür ederim!
EvertW

Bu gerçekten çok kullanışlıdır ve -E tek dosyalar için çok uygundur.
Subin Sebastian


1

Message.cpp veya .c dosyası olarak bir dosyamız olduğunu varsayalım

Adım 1: Önişleme (Bağımsız Değişken -E)

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

Oluşturulan P1 dosyası genişletilmiş makrolara ve başlık dosyası içeriğine sahiptir ve yorumlar kaldırılmıştır.

Adım 2: Önceden işlenmiş dosyayı montaja çevirin (Bağımsız Değişken-S). Bu görev derleyici tarafından yapılır

g ++ -S. \ Message.cpp

Bir assembler (ASM) oluşturulur (Mesaj.s). Tüm montaj koduna sahiptir.

Adım 3: Montaj kodunu Nesne koduna çevirin. Not: Message.s, 2. Adımda oluşturulmuştur. g ++ -c. \ Message.s

Message.o adında bir Nesne dosyası oluşturulur. İkili formdur.

Adım 4: Nesne dosyasını bağlama. Bu görev bağlayıcı tarafından yapılır

g ++. \ Message.o -o MessageApp

MessageApp.exe bir exe dosyası burada oluşturulur.

#include <iostream>
using namespace std;

 //This a sample program
  int main()
{
cout << "Hello" << endl;
 cout << PQR(P,K) ;
getchar();
return 0;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.