web-dev-qa-db-ja.com

gccは前処理後にCコードを出力できますか?

私は、C以外の多くの言語をサポートするために多くのプリプロセスディレクティブを持っていると思われるオープンソースライブラリを使用しています。 、私が書いているようなもの。

Gcc(またはLinuxで一般的に利用可能な他のツール)はこのライブラリを読み取ることができますが、プリプロセスが何にでも変換され、人間にも読めるCコードを出力できますか?

85
LGTrader

はい。 gccに-Eオプションを渡します。これにより、前処理されたソースコードが出力されます。

177
mipadi

cppはプリプロセッサです。

cpp filename.cを実行して前処理されたコードを出力するか、cpp filename.c > filename.preprocessedでファイルにリダイレクトします。

62
tpdi

私はgccをプリプロセッサ(htmlファイル用)として使用しています。それはまさにあなたが望むものです。 「#-」ディレクティブを展開し、読み取り可能なファイルを出力します。 (私がこれを試みた他のC/HTMLプリプロセッサはありません。行を連結したり、特殊文字でチョークしたりします。)gccがインストールされていると仮定すると、コマンドラインは次のようになります。

gcc -E -x c -P -C -traditional-cpp code_before.cpp> code_after.cpp

( 'cpp'である必要はありません。) http://www.cs.tut.fi/~jkorpela/html/cpre.html にこの使用法の優れた説明があります。

「-traditional-cpp」は空白とタブを保持します。

13
Jack Ritter

実行:

gcc -E <file>.c

または

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

-save-temps

これも念頭に置いておくべきもう1つの優れたオプションです。

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

main.c

#define INC 1

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

そして今、通常の出力main.oに加えて、現在の作業ディレクトリには次のファイルも含まれています。

  • main.iは、以下を含む目的の事前所有ファイルです。

    # 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はボーナスです:-)、生成されたアセンブリが含まれます:

        .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
    

多数のファイルに対して実行する場合は、代わりに次の使用を検討してください。

 -save-temps=obj

これにより、現在の作業ディレクトリではなく、-oオブジェクトの出力と同じディレクトリに中間ファイルが保存されるため、潜在的なベース名の競合が回避されます。

-Eに対するこのオプションの利点は、ビルド自体にあまり干渉することなく、ビルドスクリプトに簡単に追加できることです。

このオプションのもう1つの素晴らしい点は、-vを追加する場合です。

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

/tmpの下の見苦しい一時ファイルの代わりに使用されている明示的なファイルを実際に示しているため、前処理/コンパイル/アセンブリ手順を含む、何が起こっているかを正確に把握するのは簡単です。

/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でテスト済み。

Message.cppまたは.cファイルとしてファイルがあるとします

ステップ1:前処理(引数-E)

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

生成されたP1ファイルにはマクロとヘッダーファイルの内容が展開されており、コメントは削除されています。

ステップ2:前処理済みファイルをアセンブリに変換します(引数-S)。このタスクはコンパイラーによって行われます

g ++ -S。\ Message.cpp

アセンブラー(ASM)が生成されます(Message.s)。すべてのアセンブリコードが含まれています。

ステップ3:アセンブリコードをオブジェクトコードに変換します。注:Message.sはStep2で生成されました。 g ++ -c。\ Message.s

Message.oという名前のオブジェクトファイルが生成されます。これはバイナリ形式です。

ステップ4:オブジェクトファイルのリンク。このタスクはリンカーによって行われます

g ++。\ Message.o -o MessageApp

ExeファイルMessageApp.exeがここで生成されます。

#include <iostream>
using namespace std;

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