【C 语言】编译过程 分析 ( 预处理 | 编译 | 汇编 | 链接 | 宏定义 | 条件编译 | 编译器指示字 )
相關文章鏈接 :
1.【嵌入式開發】C語言 指針數組 多維數組
2.【嵌入式開發】C語言 命令行參數 函數指針 gdb調試
3.【嵌入式開發】C語言 結構體相關 的 函數 指針 數組
4.【嵌入式開發】gcc 學習筆記(一) - 編譯C程序 及 編譯過程
5.【C語言】 C 語言 關鍵字分析 ( 屬性關鍵字 | 常量關鍵字 | 結構體關鍵字 | 聯合體關鍵字 | 枚舉關鍵字 | 命名關鍵字 | 雜項關鍵字)
- 一 編譯過程
- 編譯過程圖解
- 步驟1 編譯預處理
- 1 預編譯處理內容
- 2 預編譯處理代碼示例 驗證 include define 注釋 處理過程
- 步驟2 編譯
- 1 編譯 中的操作
- 2 編譯 示例
- 步驟3 匯編
- 1 匯編 中的操作
- 2 匯編 示例
- 單步編譯 示例 預處理 編譯 匯編 鏈接
- 鏈接器
- 1 鏈接器簡介
- 2 靜態鏈接
- 3 動態鏈接
- 二 宏定義 使用詳解
- 宏定義 常量
- 宏表達式
- 1 宏表達式簡介
- 2 宏表達式 代碼示例
- 3 宏表達式 與 函數對比
- 宏表達式 或 宏常量 作用域限制
- 1 宏定義 沒有作用域限制
- 2 undef 限制宏定義 作用域
- 內置宏
- 1 內置宏 簡介
- 2 日志宏 代碼示例
- 三 條件編譯
- 基本概念
- 1 條件編譯簡介
- 2 條件編譯 示例 簡單的條件編譯 修改代碼實現
- 3 條件編譯 示例 使用命令行生成宏定義控制條件編譯 不修改代碼實現
- include 間接包含
- 1 間接包含 介紹
- 2 include 間接包含 示例 錯誤示例 解決方案
- 2 include 間接包含 示例 正確的處理方法
- 條件編譯控制示例 編譯不同產品 控制開發版本和發布版本編譯
- 基本概念
- 四 編譯指示字 error line
- error 編譯指示字
- 1 error 簡介
- 2 error warning 代碼示例
- line 編譯指示字
- 1 line 簡介
- 2 line 代碼示例
- pragma 編譯器指示字
- 1 pragma 簡介
- 2 pragma message 參數
- 3 pragma pack 參數
- error 編譯指示字
- 五 運算符
- 運算符
- 運算符
一. 編譯過程
1. 編譯過程圖解
編譯過程 :
編譯過程 : 預處理 -> 編譯 -> 匯編 -> 鏈接;
1. 編譯預處理 : 產生 .i 后綴的預處理文件;
2. 編譯操作 : 產生 .s 后綴的匯編文件;
3. 匯編操作 : 產生 .o 后綴的機器碼二進制文件;
4. 鏈接操作 : 產生可執行文件 ;
2. 步驟1 : 編譯預處理
(1) 預編譯處理內容
預編譯操作 :
- 1.處理注釋 : 刪除所有的注釋, 使用空格取代注釋內容;
- 2.處理宏定義 : 刪除所有的 #define 宏定義, 替換 代碼中 宏定義 對應 的 內容;
- 3.處理條件編譯指令 : 處理 #if, #else, #ifdef, #elif, #endif 等條件編譯指令 ;
- 4.處理#include : 處理 #include, 將被包含的文件拷貝到代碼中.
- 5.處理#pragma : 編譯器使用的 # program 指令 保留下來, 這個指令是 C 代碼 到 匯編 代碼 進行 處理的指示字.
預處理指令 : gcc -E test_1.c -o test_1.i
(2) 預編譯處理代碼示例 (驗證 #include | #define | 注釋 處理過程)
編譯預處理示例 :
- 1.代碼示例 :
- 2.預處理 : 使用 gcc -E test_1.c -o test_1.i 命令進行預處理, 預處理完之后生成 test_1.i 文件.
- 3.查看預處理文件 : 查看 test_1.i 文件 ;
test_1.i 出現了800多行的預處理文件, 原因是 #include < stdio.h >, 將 stdio.h 的文件拷貝了進來, 如果去掉了 #include 聲明, 那么預處理文件就很小.
刪除了 # include 代碼 :
- 1.代碼示例 :
- 2.預處理 : 使用 gcc -E test_1.c -o test_1.i 命令進行預處理;
- 3.查看預處理文件 :
如果沒有了 #include 聲明, 那么預編譯后的文件會大大減少.
3. 步驟2 : 編譯
(1) 編譯 中的操作
編譯 步驟中的操作 :
- 1.詞法分析 : 分析 關鍵字, 標識符, 立即數 的合法性;
- 2.語法分析 : 檢查 代碼 是否遵循 C 語言語法規則;
- 3.語義分析 : 分析表達式是否合法;
編譯 需要的指令 : gcc -S test_1.c -o test_1.s ;
(2) 編譯 示例
編譯 示例 :
- 1.代碼內容 :
- 2.執行編譯內容 : 執行 gcc -S test_1.c -o test_1.s 命令, 得到 test_1.o 文件.
- 3.查看編譯結果 : 查看生成的 test_1.s 文件, 是一個匯編文件 ;
4. 步驟3 : 匯編
(1) 匯編 中的操作
匯編 操作 :
- 1.執行者 : 匯編器;
- 2.操作 : 使用 匯編器 將 匯編代碼, 轉化為 機器可執行的 機器碼.
匯編 命令 : gcc -c test_1.s -o test_1.o ;
每條匯編指令都對應著指定的機器碼 .
(2) 匯編 示例
匯編 過程示例 :
- 1.代碼內容 :
- 2.執行編譯內容 : 執行 gcc -S test_1.c -o test_1.s 命令, 得到 test_1.o 文件.
- 3.查看編譯結果 : 查看生成的 test_1.s 文件, 是一個匯編文件 ;
- 4.匯編 : 執行 gcc -c test_1.s -o test_1.o 命令, 得到 test_1.o 文件 ;
5. 單步編譯 示例 ( 預處理 | 編譯 | 匯編 | 鏈接)
單步編譯示例 :
- 1.代碼結構: 頭文件 test_1.h, 代碼文件 test_1.c ;
- 2.頭文件代碼 :
- 3.主要邏輯代碼 :
- 4.進行預編譯 : 執行 gcc -E test_1.c -o test_1.i 指令, 會生成 test_1.i 文件;
5.預編譯目標結果文件 : test_1.i 文件;
分析 test_1.i 文件:
- 拷貝包含文件 : #include “test_1.h” 直接將 test_1.h 中的內容拷貝到 test_1.i 文件中 , 8 ~ 13 行是 test_1.h 文件拷貝到 test_1.i 中的內容.
- 編譯器注釋說明 : #部分不管, 是編譯器生成的說明 ;
- 處理注釋 : 將注釋使用空格替換, test_1.i 中 8 ~ 12 行 5 行是空格, 第 8, 9, 12 行對應著 test_1.h 中的注釋, 第十行對應著 test_1.h 中的宏定義, 第11行對應著空白行.
- 替換宏定義 : 將宏定義的位置替換到代碼中, 宏定義行使用空格替代 , 其中 8 ~ 12 行空行, 第10行就是宏定義刪除后的空行 ; 代碼中 MIN(a,b) 的位置 被 (((a)>(b)) ? (b) : (a)) 替換, SMALL 被 666 替換, BIG 被 888 替換.
6.編譯 產生 匯編文件 : 執行 gcc -S test_1.i -o test_1.s 命令 , 生成了 test_1.s 文件,
- 7.將匯編文件轉為機器碼 : 執行指令 gcc -C test_1.s -o test_1.o , 生成 test_1.o 文件 , 生成的機器碼是二進制的文件, 使用 文本編輯器打不開, 在 Windows 中使用 010Editer 打開查看二進制內容 ;
6. 鏈接器
(1) 鏈接器簡介
鏈接器簡介 :
- 1.銜接模塊引用 : 軟件各個模塊之前會相互調用, 鏈接器就是處理這些相互引用的位置之間的銜接 .
鏈接器 模塊拼裝 :
- 1.普通鏈接 : 運行時, 將所有的代碼庫 .o 文件, 一次性拷貝到內存中, 如果運行多個副本, 那么相同的代碼庫會各自占用一部分內存, 這些內存中存儲的東西是一樣的.
- 2.靜態鏈接 : 出于節省內存的考慮, 我們可以將相同的代碼封裝到靜態庫中, 那么多個副本同時運行時, 只加載一份靜態庫即可, 這樣相對于普通鏈接來說節省內存, 內存消耗比動態鏈接要多.
- 3.動態鏈接 : 運行開始的時候只加載必要的模塊, 當開始調用某一動態鏈接庫時, 才去尋找并加載動態鏈接庫到內存中, 節省內存, 但是運行效率慢.
(2) 靜態鏈接
靜態鏈接 :
- 1.加載時機 : 靜態庫中的代碼, 在運行開始前就全部加載到內存中, 這與動態鏈接中
- 2.加載份數 : 在內存中, 靜態庫只加載一次, 第一次執行程序用到靜態庫時, 加載靜態庫, 當再次運行時, 繼續復用第一次加載靜態庫, 這樣比較節省內存.
靜態鏈接圖示 :
當運行2個a.out 時, 對于靜態庫 test_3.a 只需要加載 1 次, 但是對于 test_1.o 和 test_2.o 需要各自加載一次.
靜態庫鏈接內存圖 :
(3) 動態鏈接
動態鏈接 :
- 1.加載時機 : 程序運行時不加載動態鏈接庫, 程序執行調用動態鏈接庫函數的時候, 才動態的加載動態鏈接庫 .
- 2.執行效率 : 動態鏈接效率 比 靜態鏈接要低, 因為其執行的時候, 需要搜索并加載動態鏈接, 這樣會消耗一定的性能 ;
動態鏈接圖解 :
二. 宏定義 使用詳解
1. 宏定義 常量
宏定義 常量 :
- 1.#define 定義 常量, 只是進行簡單的代碼替換.
- 2.#define 定義的不是真正意義的常量, 只是進行簡單的代碼替換, 下面代碼中的內容都是合法的.
2. 宏表達式
(1) 宏表達式簡介
宏表達式 #define :
- 1.本質不是函數 : 使用 # define 表達式, 有函數的假象, 但是其并不是函數;
- 2.功能強大, 但容易出錯 : 某些用法 生硬的替換代碼 可能導致出現 出錯的情況.
- 3.宏使用示例 :
- 4.執行結果 :
(2) 宏表達式 代碼示例
宏替換代碼示例 :
- 1.原始 C 代碼 (含有宏定義) :
- 2.預處理宏替換結果 : test_1.c 進行預處理后的 test_1.i, 使用 gcc -E test_1.c -o test_1.i 命令進行預處理;
- 3.執行結果 :
(3) 宏表達式 與 函數對比
宏表達式 與 函數對比 :
- 1.對編譯器透明 : 宏表達式在預編譯階段進行替換處理, 編譯器不知道宏的存在;
- 2.運算方面 : 宏替換不進行任何運算, 沒有實參形參的概念, 全部都是機械的替換, 宏表達式參數可以使變量,也可以是類型;
- 3.調用開銷方面 : 宏表達式不消耗任何調用開銷, 沒有函數調用開銷, 其在預處理階段就被替換了;
- 4.關于遞歸 : 宏表達式不能使用遞歸定義宏;
遞歸代碼示例 (錯誤示例) :
- 1.宏遞歸代碼示例 :
- 2.預編譯結果 : 宏替換后的結果 ;
- 3.編譯結果 : 編譯報錯, 提示沒有定義 FAC() 方法 ;
3. 宏表達式 或 宏常量 作用域限制
(1) 宏定義 沒有作用域限制
宏定義作用域限制 :
- 1.宏定義位置 : 宏定義可以再程序的任意位置定義, 甚至是函數內部;
- 2.宏定義使用位置 : 宏定義可以再任何位置使用;
- 3.代碼示例 :
- 4.預編譯結果 :
- 5.執行結果 :
(2) #undef 限制宏定義 作用域
限制宏定義作用域 #undef 用法 :
- 1.使用方法 : 定義宏 #define MIN 100 之后, 可以使用 #undef MIN 限制其作用范圍, 只能在 #define 和 #undef 之間使用該宏, 在 #undef 之后就不可使用該宏了;
- 2.使用示例 (錯誤示例) :
- 3.預編譯結果 :
- 4.編譯報錯內容 :
4. 內置宏
(1) 內置宏 簡介
內置宏舉例 :
- 1.__FILE__ : 代表被編譯的文件名稱 ;
- 2.__LINE__ : 代表當前的行號 ;
- 3.__DATE__ : 代表當前的日期 ;
- 4.__TIME__ : 代表編譯時的時間 ;
- 5.__STDC__ : 編譯器是否遵循 標準 C 規范 ;
(2) 日志宏 代碼示例
使用宏定義日志打印 :
- 1.代碼示例 :
- 2.運行結果 :
日志宏 : 打印日志的同時, 打印當前的文件名稱, 代碼行號, 當前運行時間 ;
三. 條件編譯
1. 基本概念
(1) 條件編譯簡介
條件編譯指令 :
- 1.指令 : #if , #ifdef, #ifndef, #else, #endif 等 ;
- 2.用法 : 與 if else 等用法類似, 具體查看下面的示例, 但是 #if, #else, #endif 是預編譯階段被預編譯處理的, if else 是在編譯階段, 被編譯器處理, 是要被編譯到目標代碼中的 ;
- 3.作用 : 條件編譯指令是預編譯指令, 控制某段代碼是否被編譯, 可以按照不同的條件選擇性編譯指定的代碼段, 選擇性的忽略某段代碼, 用以編譯出不同功能的可執行目標文件 ;
條件編譯的應用環境 :
- 1.軟件分支維護 : 維護一個軟件的不同分支, 控制軟件分支編譯;
- 2.區分版本 : 區分軟件調試版本 和 正式上線的版本, 開發版本肯定有很多調試信息, 正式版沒有冗余的信息;
條件編譯 注意點 :
- 1.命令行定義宏 : 可以使用 gcc -D 選項來定義宏, 如 gcc -DDEBUG test_1.c 等價于 #define DEBUG, gcc -DMIN=1 test_1.c 等價于 #define MIN 1 語句 ;
- 2.條件編譯處理頭文件包含問題 : #include 會出現多重嵌套問題, 使用 #ifndef _HEAD_H_ | #define _HEAD_H_ | #endif 可以解決頭文件多次引用的問題 ;
- 3.使用一套代碼維護不同產品 : 開發中, 可以條件編譯來維護一套代碼, 編譯出不同的產品 ;
- 4.開發板和正式版區分 : 使用條件編譯可以區分產品的開發調試版本 和 正式發布版本 ;
(2) 條件編譯 示例 (簡單的條件編譯 | 修改代碼實現)
通過修改代碼 控制 條件編譯 代碼示例 :
- 1.代碼1 :
- 2.條件編譯 預編譯結果 : 使用 gcc -E test_1.c -o test_1.i 命令進行預編譯 ;
- 3.執行結果 :
修改代碼后 刪除宏定義 :
- 1.代碼2 :
- 2.條件編譯 預編譯結果 :
- 3.執行結果 :
上述兩個例子, 主要是通過在代碼中定義 宏常量, 來控制條件編譯中, 哪些語句需要編譯, 哪些語句在預編譯階段就要刪除 ;
(3) 條件編譯 示例 ( 使用命令行生成宏定義控制條件編譯 | 不修改代碼實現)
使用命令行定義宏 從而控制條件編譯, 代碼不變 :
- 1.代碼 :
- 2.命令行1 : 使用命令行命令 gcc -DC=1 -E test_1.c -o test_1.i, 該命令 等價于 定義 宏 #define C 1, 下面是預編譯結果 和 執行結果 ;
- 3.命令行2 : 使用命令行命令*gcc -DC=2 -E test_1.c -o test_1.i, 該命令等價于 定義宏 #define C 2, 下面是預編譯結果 和 執行結果 ;
2. #include 間接包含
(1) 間接包含 介紹
#include 間接包含 :
- 1.#include作用 : #include 作用是 單純的 將 文件內容 嵌入 到 當前的 文件 ;
- 2.間接包含 : #include 會有間接包含的情況, 如 包含的 文件中, 有重復包含的情況 ;
(2) #include 間接包含 示例 ( 錯誤示例 | 解決方案 )
間接包含 結構圖示 : test_1.c 文件包含 三個頭文件, test_1.h 包含的 test_2.h 頭文件 與 test_1.c 包含的該頭文件相同, 同一個頭文件被導入了2次, 因此編譯時會報錯;
間接包含 代碼示例 :
- 1.test_1.c 代碼 :
- 2.test_1.h 頭文件代碼 :
- 3.test_2.h 頭文件代碼 :
- 4.預編譯結果 : 同時拷貝了兩份 int test_2_variable = 666; 語句, 如果進入編譯階段, 肯定是重復定義變量 ;
- 5.編譯報錯內容 :
間接包含 簡單解決方案 : 下面的代碼與上面的唯一區別是, test_1.c 中注釋掉了 #include “test_2.h” 語句.
- 1.test_1.c 代碼 :
- 2.test_1.h 頭文件代碼 :
- 3.test_2.h 頭文件代碼 :
- 4.執行結果 :
(2) #include 間接包含 示例 ( 正確的處理方法 )
使用 #ifndef , #define 和 #endif 語句處理頭文件包含情況 :
- 1.主代碼 test_1.c :
- 2.頭文件1 test_1.h :
- 3.頭文件2 test_2.h :
- 4.預編譯結果 :
- 5.代碼執行結果 :
3. 條件編譯控制示例 ( 編譯不同產品 | 控制開發版本和發布版本編譯)
條件編譯控制代碼示例 :
- 1.代碼 :
- 2.編譯產品1代碼開發版本(debug)并執行 : 產品1 的 debug 版本需要定義 DEBUG宏 和 PRODUCT_1 宏, 使用命令 gcc -DDEBUG -DPRODUCT_1 test_1.c 進行編譯即可 ;
- 3.編譯產品2代碼開發版本(bebug)并執行 : 產品2 debug 版本, 不需要定義 PRODUCT_1 宏, 但是需要定義 DEBUG 宏, 使用命令 gcc -DDEBUG test_1.c 進行編譯即可;
- 4.編譯產品1代碼發布版本(release)并執行 : 產品1的release 版本, 不定義 DEBUG 宏, 但是需要定義 PRODUCT_1 宏, 使用命令 gcc -DPRODUCT_1 test_1.c 即可 ;
- 5.編譯產品2代碼發布版本(release)并執行 : 產品2的release版本, 只需要不定義 DEBUG宏 和 PRODUCT_1宏即可, 使用 gcc test_1.c 命令 ;
四. 編譯指示字 ( #error | #line )
1. #error 編譯指示字
(1) #error 簡介
#error簡介 :
- 1.#error 作用 : #error 編譯指示字 用于生成 編譯錯誤信息, 立即終止編譯 ; 這個編譯錯誤是程序員自定義的編譯錯誤信息;
- 2.#error 用法 : #error error_message, 這個 error_message 是字符串, 不需要使用 “” 包起來;
#warning 也是編譯指示字, 用于在編譯時生成警告信息, 但是編譯的過程不會終止, 會繼續編譯下去 ;
(2) #error #warning 代碼示例
#error #warning 代碼示例 :
- 1.代碼 :
- 2.編譯結果( 命令行中定義指定的宏 ) : 使用 gcc -DMAX test_1.c 命令編譯, 此處定義了 MAX 宏, 編譯執行成功.
- 3.編譯結果( 命令行中不定義指定的宏 ) : 使用 gcc test_1.c 命令編譯, 此處沒有命定義 MAX 宏, 編譯時報錯.
- 4.單步操作預編譯結果 (定義宏) : 使用 gcc -DMAX -E test_1.c -o test_1.i 命令, 進行預編譯, 結果預編譯成功, 查看預編譯生成的 test_1.i 文件 ;
- 5.單步操作預編譯結果 (不定義宏) : 使用 gcc -E test_1.c -o test_1.i 命令, 進行預編譯, 結果預編譯也停止了, 沒有生成 test_1.i 文件, 因此#error 和 #warning 是在預編譯階段進行處理的 ;
2. #line 編譯指示字
(1) #line 簡介
#line 簡介 :
- 1.#line 作用 : 用于修改當前的 __LINE__ 和 __FILE__ 的內置宏 ;
- 2.#line 用法 : #line 行號 文件名 , 即將當前的 內置宏 __LINE__ 設置為 行號, __FILE__ 設置為 文件名 ;
- 3.使用環境 : 調試代碼時, 編譯 查錯 的時候, 設置自己關心的代碼, 這是很古老的調試方法, 該技術已經被淘汰 ;
(2) #line 代碼示例
#line 使用代碼示例 :
- 1.代碼示例 :
- 2.執行結果 :
3. #pragma 編譯器指示字
(1) #pragma 簡介
#pragma 編譯器指示字 簡介 :
- 1.#pragma 作用 : 該 編譯器指示字 指示編譯器完成一些特定的操作 ;
- 2.編譯器特有, 不可移植 : #pragma 的很多指示字 參數, 這些參數 都是編譯器 特有的, 編譯器指示字 在 編譯器之間不通用, 不可移植 ;
- 3.忽略不識別的指令 : 如果編譯器不支持某個 #pragma 指令 參數, 預處理器會忽略這條指令, 并將其刪除;
- 4.相同指令 操作不同 : 每個編譯器對 #pragma 指令定義都不同, 可能存在兩個相同的 #pragma 指令在不同的編譯器中執行不同的操作 ;
#pragma 用法 : #pragma 參數
(2) #pragma message 參數
#pragma message 參數 :
- 1.作用 : 編譯器編譯時將編譯信息輸出到窗口中 ;
- 2.與 #error 編譯器指示字對比 : #error只是在出現錯誤的時候, 將錯誤信息輸出出來, #pragma message 是單純的額將所有信息輸出出來, 不管對錯 ;
- 3.代碼示例 :
- 4.不定義宏進行編譯 : 如果既不定義 MAX 宏, 也不定義 MIN 宏, 那么直接執行 #error 報錯;
- 5.定義 MAX 宏并執行 :
(3) #pragma pack 參數
內存對齊 簡介 :
- 1.內存對齊概念 : 不同類型的數據存放在內存中, 但是其存放順序不是順序存放, 而是按照內存對齊規則進行排列 ;
- 2.內存對齊原因 : ① 出于性能考慮 , CPU 讀取內存不是想讀取多少就讀取多少, 其內存讀取是分塊讀取的, 塊大小只能是 2 的n次方字節, 如 1, 2, 4, 8, 16, 字節, 如果被讀取的數據沒有對齊, 那么需要多次讀取, 這樣性能就降低了 ; ② 硬件平臺限制 : 可能存在某些硬件只能讀取偶數地址, 一旦讀取奇數地址, 直接出現硬件異常導致程序掛掉;
- 3.內存對齊設置不能高于編譯器默認對齊字節數 : GCC 編譯器默認支持 4 字節對齊, 那么使用 #pragma pack() 只能設置 1字節 或 2 字節, 4 字節支持, 不能設置其它支持方式; 如果編譯器默認是 8 字節, 那么只能設置 1, 2, 4, 8 四種字節對齊方式, 只能往低設置, 不能高于編譯器默認的對齊字節數;
結構體 struct 占用內存計算方式 :
- 1.第一個起始位置 : 第一個元素 在 第一個位置, 從 偏移量 0 開始;
- 2.對齊參數 : 對齊數 和 類型大小 之間較小的一個是 對齊參數 ; 這里要注意 如果有結構體元素, 那么該結構體元素的對齊參數就是 結構體中的最大對齊參數;
- 3.從第二個開始的起始位置 : 除第一個之外的起始位置, 都必須整除對應的 對齊參數 ;
- 4.最終計算大小要整除所有的對齊參數 ;
- 5.注意結構體中有結構體元素 : 結構體中的結構體元素對齊數是結構體元素中的最大對齊數 ;
- 5.代碼示例 :
- 6.執行結果 :
五. #運算符
1. #運算符
#運算符作用 :
- 1.將宏參數轉為字符串 : # 運算符 可以在 編譯 的 預編譯 階段, 將宏定義中的參數, 轉化為 字符串 ;
- 2.預處理器開始符號 : 預處理器 開始處理 的符號 ;
- 3.#運算符代碼示例 :
- 4.預編譯結果 : 使用 “gcc -E test_1.c -o test_1.i” 指令進行預編譯, 可以看到 # 運算符將 宏定義參數轉為字符串 ;
# 運算符 將 Hello 666 main 轉為 “Hello” “666” “main” 字符串, 將 square 轉為了 “square” 字符串 ;
- 5.編譯執行最終結果 :
2. ##運算符
## 運算符作用 :
- 1.作用 : 在預編譯階段粘連兩個符號 ;
- 2.代碼示例 :
- 3.預編譯結果 : 使用 “gcc -E test_1.c -o test_1.i” 命令, 執行預編譯 ;
- 4.最終編譯執行結果 :
總結
以上是生活随笔為你收集整理的【C 语言】编译过程 分析 ( 预处理 | 编译 | 汇编 | 链接 | 宏定义 | 条件编译 | 编译器指示字 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java 语言】Java 多线程 一
- 下一篇: 【C 语言】指针 与 数组 ( 指针 |