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


104

C以外の多くの言語をサポートするために多くの前処理ディレクティブが含まれていると思われるオープンソースライブラリを使用しています。ライブラリが何をしているかを調査できるように、前処理後にコンパイルしているCコードを確認したいと思います。 、私が書いたものに似ています。

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


前処理されたコードにはプリプロセッサディレクティブがなくなりますが、前処理される前よりもはるかに読みにくくなると確信しています...
Alex W

2
@AlexW-それは、コードを書いている人々がプリプロセッサをいかに酷使したかに完全に依存します。
架空の名前

1
承認された回答をここで変更することを検討してください。 gcc -Eで動作するように行を書き直す必要があるよりも便利ですcpp
グレイ

回答:


193

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


12
コンパイラー・コマンドにすでにパラメーターがある-o something.o場合は、それをに変更することもできます-o something.i。それ以外の場合、前処理された出力は.oファイル内にあります。
Tor Klingberg、2015年

@TorKlingberg一度に複数のファイルに対してこれを実行できますか?
user2808264 2016

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

68

cpp プリプロセッサです。

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


2
cppを直接示しているので、これが最良の答えだと思います。Linuxシステム(少なくともManjaro)にも、デフォルトで-Eがあるようです。どちらの方法でも、このコマンドから同じ結果が得られます。diffファイルに違いはありません。これは、マクロのエラーを探すコードを前処理するための便利な方法のようにも見えます。素晴らしい質問と素晴らしい答え(IALCTHW)。
lee8oi 2018

17

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

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

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

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


おかげで、これはpython cffi cdefを生成するのに非常に役立ちます!
amirouche

13

-save-temps

これは、心に留めておくとよい別のオプションです。

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


1
ビルドスクリプトの全体的な動作を変更せずに-save-tempsをCFLAGSに追加するだけなので、-Eよりもはるかにエレガントです。ありがとうございました!
EvertW

これは確かに非常に便利で、-Eは単一ファイルに対して非常に便利です。
Subin Sebastian


1

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

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

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

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

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

g ++ -S。\ Message.cpp

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

手順3:アセンブリコードをオブジェクトコードに変換します。注:Message.sはステップ2で生成されました。 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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.