6.1.前処理は何をしましたか.


私たちが書いたソースコードからCPUが認識して実行できるバイナリに至るまで、多くのことが起こっています.C言語の前処理を深く検討してみましょう.
1.ソースコードから実行可能プログラムへのプロセス(1)ソースコード.cファイルは、まずプリプロセッサを介して中間ファイルを生成する.iファイル(2).iファイルはコンパイルによりアセンブリを生成する.sファイル(3).sのアセンブリファイルはアセンブリによって生成する.oのターゲットファイル(4).oのターゲットファイルはリンクによって生成する.Elf実行可能プログラム
各ステップには対応するツールがあり、前処理にはプリプロセッサがあり、コンパイラがコンパイルされ、リンクにはリンクがあり、これらのツールが結合してコンパイルツールチェーンと呼ばれています.windos上のコンパイラでは、これらはいわゆるコンパイラによって遮断されています.コンパイル機能は1つしか残っていませんが、コンパイラというのは正確ではありません.Linuxでは、gccはコンパイルツールチェーンです.gccには、プリプロセッサ、コンパイラ、アセンブリ、リンクなどが含まれています.
2.gccではプリプロセッシングのみでコンパイルしない方法
gcc xx.c-oは、ソースコードから実行可能プログラムgcc xxに移行する.c-c-oはコンパイルのみ接続せず、生産する.oの目標ファイルgcc-E xx.c -o xx.i生成された中間ファイルのみを前処理する
前処理のみの中間ファイルを見ると、前処理プロセスのデバッグと研究に役立ちます.前に述べた#defineとtypedefの詳細の違いを覚えていますか.次に、前処理がどのようなプロセスであるかを分析します.
#include

#define pchar char*
void main(void)
{
    pchar p1,p2;
}

//       ,gcc -E xx.c -o xx.i       

#include


void main(void)
{
    char* p1,p2;
}

解析:(1)前処理後、元の#defineコードがなくなり、そのままその位置で置換する(2)#defineの置換は簡単な置換であり、すべてのpcharをchar*で置換する(3)p 1,p 2のタイプを見る.p 1 shi char*タイプ、p 2はcharタイプのみ
typedefの使用を見てみましょう
#include

typedef char* pchar
void main(void)
{
    pchar p1,p2;
}

//    

typedef char * pchar;

void main(void )
{

 pchar p1,p2;

}

私たちは変化がないことに気づいた.すなわちtypedef再定義のタイプは,前処理段階では変化せず,コンパイル段階で機能する.コンパイル段階ではpcharを通常のchar*として使用する.
3.ヘッダファイルは前処理段階でどのように変化しますか?(1)2つの含み方がある1つ目:#include<>2つ目:#include」1つ目はシステムが提供するヘッダファイルを含む2つ目はプログラマーが自分で書いたヘッダファイルを含む
(2)2つの違い1つ目:#include<>の方法で、C言語コンパイラはシステムが指定したディレクトリ(コンパイラが構成したディレクトリ)にこのヘッダファイルを探すだけで、見つからないとエラーになります.ただし、コンパイラでは、-iコマンドを使用してシステムディレクトリにディレクトリを追加できます.(現在のディレクトリは見つかりません)
2つ目の方法:#include""の方法では、コンパイラはまず現在のディレクトリを探し、見つからない場合はシステムが指定したディレクトリを探します.この方法にはシステムファイルも含まれます.
まとめ:(1)システムヘッダファイルを含むには「」を用いることができるが,一般的には一定のルールに従う.システムファイルは<>,自分で書いたものは""を用い,自分で書いた大量のヘッダファイルも<>を用いてコンパイラが指定したディレクトリに追加すればよい.(2)(ヘッダファイルに含む実質)は1.cには1が含まれる.h,つまり1.hのコードはそのまま1に書く.c中#include<>文の元の場所へ行きます.
—-1.cファイル--
# nclude"1.h"
main()
{
    c = a + b;
    printf("c = %d
"
,c); }
----1.h  ----

int a = 1;
int b = 2;
int c = 0;  

前処理の命令:gcc-E 1.c -o 1.i
結果
# 1 "1.c"
# 1 ""
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "" 2
# 1 "1.c"
# 1 "1.h" 1
int a = 1;
int b = 2;
int c = 0;
# 2 "baohan.c" 2
main()
{
 c = a + b;
 printf("c = %d
"
,c); }

分析:(1)前に私たちの知らないものがたくさんあって、それを気にしないで、それはコンパイラに見せたのです.(2)は1.cの#include 1.h」というコードで、1.hのコードはすべてここにコピーされた.(3)我々が書いたコードは前処理後に1つ生成することに注意する.iファイルは、すべての変更があります.iファイルにあります.もとのc書類の補充が変更されました.
4.前処理段階でのコメントの変更
2つの条件コンパイル#iddefと#if()
#include
//    
void test(void);
void main()
{
    //    
    int a = 1;
    int b = 2;
}

前処理後
#include

void test(void);
void main()
{

    int a = 1;
    int b = 2;
}

すべてのコメントが削除されたことに気づきました.
まとめ:(1)注釈は人に見せるもので,コンパイラは見なくてもよい.(2)前処理段階では,プリプロセッサはすべてコメントを削除する.つまり、コンパイル時にコンパイラは注釈とは何かを全く知らない.(3)プリプロセッサは、前処理後の中間ファイルに変更する.i、ソースコードではない.c
5.条件コンパイルは前処理段階で何が起こったのですか.
#include

#define test 3 //    test  3 

void main(void)
{

        #ifdef test 3   //   test        3, 
        printf(" test 3  !
"
); #else // printf("else !
"
); #endif }

前処理後の前処理後に含むstdio.hは書かれていません.長すぎます.
void main(void)
{


 printf(" test 3  !
"
); }

解析:前処理段階では,条件コンパイルは,どの条件が成立するかを判断し,条件が成立した文を残し,成り立たない条件のそれを切り捨てられる.(.iファイルでは.cファイルではありません)
第2の条件コンパイル#if()を見てみましょう
#include

#define ok 1

main()
{
        #if(ok)

        printf("ok
"
); #else printf("not ok
"
); #endif } // : main() { printf("ok
"
); }

まとめ:第1のifdefは、そのシンボルがマクロ定義されているか否かを判断し、破棄条件が成立していない部分で第2のif()とif()は同じである.かっこは論理真偽値です.