#ifndef main_header
#define main_header
#include "stdafx.h"
#define pi 3.1415926
struct xx
;class xx
;#endif
例1:define pi 3.1415926 就是建立起pi和3.1415926之間的對映關係,好在編譯階段將pi替換位3.1415926。
例2:ifndef/endif就是從乙個檔案中有選擇性的挑出一些符合條件的**來交給下一步的編譯階段來處理。這裡,main_header就是該段**的乙個識別符號(自定義,不可重複,常與檔名相關)。如果定義了這個巨集識別符號,這下面的**就不用編譯了,如果沒有則編譯。保證該段**只編譯一次。這個巨集命令用法強大,用處多多。詳解可以參看:
例3:啊,include!相當於把***.h檔案裡面的內容複製乙份到這條include "***.h"語句的地方來。.h裡面還有include怎麼辦?那就巢狀式繼續複製替換唄!假如下面這種情況:ab.cpp中包含a和b兩個標頭檔案,而ab都包含c標頭檔案,那就通過例2的方法保證c標頭檔案的內容只複製一次。如果在兩個不同的.cpp中同時包含f.h怎麼辦?答:各複製各的,互不干擾。c++的鐵律就是先宣告後使用,不宣告就想使用,想上天呀!哈哈!
// ab.cpp:
#include "a.h"
#include "b.h"
d::d()
// a.h:
#include "c.h"
struct a
// b.h:
#include "c.h"
struct b
主要幹的活:
1.
int n = 1;
void funa()
偏移量 內容 長度
0x0000 n 4
0x0004 funa ??
0x0004 inc dword ptr[0x0000]
0x00?? ret
extern int n;
void funb()
偏移量 內容 長度
0x0000 funb ??
0x0000 inc dword ptr[????]
0x00?? ret
符號 位址
n 0x0000
_funa 0x0004
符號 位址
_funb 0x0000
符號 位址
n 0x0001
把所有編譯好的單元全部鏈結為乙個整體檔案,這一步可以比作乙個「連線」的過程,比如a檔案用了b檔案中的函式,那麼鏈結的這一步會建立起這個關聯。
特別注意:
鏈結時最重要的一項工作就是檢查全域性空間裡面是不是有重複定義或者缺失定義,也就是:各.obj的匯出符號表中是否有重名的;各.obj的未解決符號表中存在各匯出符號表中沒有的符號。這也為什麼我們一般不在標頭檔案中出現定義,而在.cpp中定義全域性變數。因為標頭檔案有可能被多個原始檔包含,每個原始檔都會單獨編譯,鏈結時就會發現全域性空間中有多個定義了。
附錄一: 標準c和c++將編譯過程定義的9個階段(phases of translation):
檔案中的物理源字元被對映到源字符集中,其中包括三字元運算子的替換、控制字元(行尾的回車換行)的替換。許多非美式鍵盤不支援基本源字符集中的一些字元,檔案中可用三字元來代替這些基本源字元,以??為前導。但如果所用鍵盤是美式鍵盤,有些編譯器可能不對三字元進行查詢和替換,需要增加-trigraphs編譯引數。在
c++程式中,任何不在基本源字符集中的字元都被它的通用字元名替換。
2.行合併(line splicing)
以反斜槓/結束的行和它接下來的行合併。
3.標記化(tokenization)
每一條注釋被乙個單獨的空字元所替換。c++雙字元運算子被識別為標記(為了開發可讀性更強的程式,c++為非ascii碼開發者定義了一套雙字元運算子集和新的保留字集)。源**被分析成預處理標記。
4.預處理(preprocessing)
呼叫預處理指令並擴充套件巨集。使用#include指令包含的檔案,重複步驟1到4。上述四個階段統稱為預處理階段。
源字符集成員、轉義序列被轉換成等價的執行字符集成員。例如:'/a'在ascii環境下會被轉換成值為乙個位元組,值為7。
6.字串連線(string concatenation)
相鄰的字串被連線。例如:"""hahaha""huohuohuo"將成為"hahahahuohuohuo"。
7.翻譯(translation)
進行語法和語義分析編譯,並翻譯成目標**。
8.處理模板
處理模板例項。
9.連線(linkage)
解決外部引用的問題,準備好程式映像以便執行。
附錄二:
static:如果該關鍵字位於全域性函式或者變數的宣告前面,表明該編譯單元不匯出這個函式或變數,因些這個符號不能在別的編譯單元中使用(內部鏈結)。如果是static區域性變數,則該變數的儲存方式和全域性變數一樣,但是仍然不匯出符號。
外部鏈結的利弊:外部鏈結的符號在整個程式範圍內都是可以使用的,這就要求其他編譯單元不能匯出相同的符號(不然就會報duplicated external symbols)。
附錄三:using namespace
詳見:
面試問題之C 語言 簡述編譯過程
於 編譯過程主要分為四步 1 詞法分析 掃瞄 執行類似於有限狀態機的演算法將源 的字元分割成一系列的記號。詞法分析產生的記號一般分為幾種 關鍵字 識別符號 字面量 數字,字串等 特殊標記 加號,等號等 另外,掃瞄器也完成其他一些工作,比如將識別符號存放到符號表中,將數字 字串常量存放到文字表中。2 ...
c編譯過程
編譯的概念 編譯程式讀取源程式 字元流 對之進行詞法和語法的分析,將高階語言指令轉換為功能等效的彙編 再由匯程式設計序轉換為機器語言,並且按照作業系統對可執行檔案格式的要求鏈結生成可執行程式。編譯的完整過程 c源程式 預編譯處理 c 編譯 優化程式 s asm 匯程式設計序 obj o a ko 鏈...
c 編譯過程
編譯過程主要分為 4個過程 1 編譯預處理 預編譯程式完成的工作,可以說成是對源程式的 替換 工作。經過這個過程,生成乙個沒有巨集定義 沒有條件編譯指令 沒有特殊符號的輸出檔案。2 編譯 優化階段 通過詞法分析 語法分析,在確認所有的指令都符合語法規則之後,將其翻譯成等價的中間 或彙編 在c 中,以...