C語(yǔ)言 深入講解條件編譯的用處
一、基本概念
- 條件編譯的行為類似于 C 語(yǔ)言中的 if...else...
- 編譯是預(yù)編譯指示命令,用于控制是否編譯某段代碼
下面看一段簡(jiǎn)單的條件編譯的代碼:
#include <stdio.h> #define C 1 int main() { const char* s; #if( C == 1 ) s = "This is first printf...\n"; #else s = "This is second printf...\n"; #endif printf("%s", s); return 0; }
下面為輸出結(jié)果:
可以輸入gcc -E Test.c -o file.i 命令,看看預(yù)編譯階段發(fā)生了什么,下面是部分輸出結(jié)果:
# 2 "Test.c" 2 int main() { const char* s; s = "This is first printf...\n"; printf("%s", s); return 0; }
可以看到宏定義和條件編譯都沒有了,由相應(yīng)內(nèi)容取而代之。
二、條件編譯的本質(zhì)
預(yù)編譯器根據(jù)條件編譯指令有選擇的刪除代碼
編譯器不知道代碼分支的存在
if...else... 語(yǔ)句在運(yùn)行期進(jìn)行分支判斷
條件編譯指令在預(yù)編譯期進(jìn)行分支判斷
可以通過命令行定義宏
- gcc -Dmacro=value file.c
- gcc -Dmacro file.c
下面看一個(gè)通過命令行定義宏的代碼:
#include <stdio.h> int main() { const char* s; #ifdef C s = "This is first printf...\n"; #else s = "This is second printf...\n"; #endif printf("%s", s); return 0; }
終端輸入gcc -DC Test.c,輸出結(jié)果如下:
三、#include 的本質(zhì)
- #include 的本質(zhì)是將已經(jīng)存在的文件內(nèi)容嵌入到當(dāng)前文件中
- #include 的間接包含同樣會(huì)產(chǎn)生嵌入文件內(nèi)容的操作
這就出現(xiàn)一個(gè)問題,間接包含同一個(gè)頭文件是否會(huì)產(chǎn)生編譯錯(cuò)誤?
下面就來(lái)通過一段代碼深入探究:
global.h:
// global.h int global = 10;
test.h:
// test.h #include "global.h" const char* NAME = "test.h"; char* hello_world() { return "hello world!\n"; }
test.c:
#include <stdio.h> #include "test.h" #include "global.h" int main() { const char* s = hello_world(); int g = global; printf("%s\n", NAME); printf("%d\n", g); return 0; }
編譯后編譯器報(bào)錯(cuò),global 重定義:
為什么 global 會(huì)重定義呢?下面開始單步編譯,輸入gcc -E test.c -o test.i,輸出部分結(jié)果如下:
# 2 "test.c" 2 # 1 "test.h" 1 # 1 "global.h" 1 int global = 10; # 4 "test.h" 2 const char* NAME = "test.h"; char* hello_world() { return "hello world!\n"; } # 3 "test.c" 2 # 1 "global.h" 1 int global = 10; # 4 "test.c" 2 int main() { const char* s = hello_world(); int g = global; printf("%s\n", NAME); printf("%d\n", g); return 0; }
這樣就很明顯了,程序先將 test.h 里面的東西復(fù)制進(jìn) test.c,由于 test.h 里面有一個(gè) include "global.h",就把int global = 10; 復(fù)制過來(lái),然后復(fù)制
const char* NAME = "test.h";
char* hello_world()
{undefined
return "hello world!\n";
}
在然后由于test.c 里面又定義一個(gè)#include "global.h",又把int global = 10; 復(fù)制過來(lái),造成了重復(fù)定義。
條件編譯可以解決頭文件重復(fù)包含的編譯錯(cuò)誤
#ifndef _HEADER_FILE_H_ #define _HEADER_FILE_H_ //source code #endif
如果沒有定義 header_file.h,則定義,且執(zhí)行里面的代碼;否則,如果定義了,里面的代碼就不會(huì)執(zhí)行。
所以上述代碼中可以這么改:
global.h:
// global.h #ifndef _GLOBAL_H_ #define _GLOBAL_H_ int global = 10; #endif
test.h:
// test.h #ifndef _TEST_H_ #define _TEST_H_ #include "global.h" const char* NAME = "test.h"; char* hello_world() { return "hello world!\n"; } #endif
這樣編譯就能通過了
四、條件編譯的意義
條件編譯使得我們可以按不同的條件編譯不同的代碼段,因而可以產(chǎn)生不同的目標(biāo)代碼
#if...#else...#endif 被預(yù)編譯器處理,而 if...else... 語(yǔ)句被編譯器處理,必然被編譯進(jìn)目標(biāo)代碼
實(shí)際工程中條件編譯主要用于以下兩種情況:
- 不同的產(chǎn)品線共用一份代碼
- 區(qū)分編譯產(chǎn)品的調(diào)試版和發(fā)布版
下面看一段產(chǎn)品線區(qū)分及調(diào)試代碼:
product.h:
#define DEBUG 1 #define HIGH 1
test.c:
#include <stdio.h> #include "product.h" #if DEBUG #define LOG(s) printf("[%s:%d] %s\n", __FILE__, __LINE__, s) #else #define LOG(s) NULL #endif #if HIGH void f() { printf("This is the high level product!\n"); } #else void f() { } #endif int main() { LOG("Enter main() ..."); f(); printf("1. Query Information.\n"); printf("2. Record Information.\n"); printf("3. Delete Information.\n"); #if HIGH printf("4. High Level Query.\n"); printf("5. Mannul Service.\n"); printf("6. Exit.\n"); #else printf("4. Exit.\n"); #endif LOG("Exit main() ..."); return 0; }
宏 DEBUG 是指產(chǎn)品是調(diào)試版還是發(fā)布版,調(diào)試版為 1,發(fā)布版為 0, 宏 HIGH指的是產(chǎn)品是高端產(chǎn)品還是低端產(chǎn)品,高端產(chǎn)品為 1,低端產(chǎn)品為 0
如果我們想測(cè)試調(diào)試版的高端產(chǎn)品,令 DEBUG 為 1,HIGH為 0 即可:
同理,我們想測(cè)試發(fā)布版的低端產(chǎn)品,令 DEBUG 為 0,HIGH為 0 即可:
五、小結(jié)
- 通過編譯器命令行能夠定義預(yù)處理器使用的宏
- 條件編譯可以避免重復(fù)包含頭同一個(gè)頭文件
- 條件編譯是在I程開發(fā)中可以區(qū)別不同產(chǎn)品線的代碼
- 條件編譯可以定義產(chǎn)品的發(fā)布版和調(diào)試版
到此這篇關(guān)于C語(yǔ)言 深入講解條件編譯的用處的文章就介紹到這了,更多相關(guān)C語(yǔ)言 條件編譯內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)設(shè)計(jì)模式之裝飾者模式詳解
這篇文章主要介紹了C++設(shè)計(jì)模式之裝飾模式,裝飾模式能夠?qū)崿F(xiàn)動(dòng)態(tài)的為對(duì)象添加功能,是從一個(gè)對(duì)象外部來(lái)給對(duì)象添加功能,需要的朋友可以參考下2021-09-09window調(diào)用api列出當(dāng)前所有進(jìn)程示例
這篇文章主要介紹了window調(diào)用api列出當(dāng)前所有進(jìn)程示例,需要的朋友可以參考下2014-04-04C++開發(fā):為什么多線程讀寫shared_ptr要加鎖的詳細(xì)介紹
本篇文章介紹了,在C++中為什么多線程讀寫shared_ptr要加鎖的詳細(xì)說明。需要的朋友參考下2013-04-04C++ OpenCV制作黑客帝國(guó)風(fēng)格的照片
這篇文章主要介紹了如何通過C++ OpenCV制作出黑客帝國(guó)風(fēng)格的照片,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)OpenCV有一定幫助,需要的可以參考一下2022-01-01C++使用循環(huán)計(jì)算標(biāo)準(zhǔn)差的代碼實(shí)現(xiàn)
在C++中,計(jì)算標(biāo)準(zhǔn)差可以使用循環(huán)來(lái)實(shí)現(xiàn),本文給大家介紹了一個(gè)示例代碼,演示了如何使用循環(huán)計(jì)算標(biāo)準(zhǔn)差,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2023-12-12C語(yǔ)言 動(dòng)態(tài)內(nèi)存開辟常見問題解決與分析流程
動(dòng)態(tài)內(nèi)存是相對(duì)靜態(tài)內(nèi)存而言的。所謂動(dòng)態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動(dòng)態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存2022-03-03Qt數(shù)據(jù)庫(kù)應(yīng)用之實(shí)現(xiàn)數(shù)據(jù)分組導(dǎo)出
這篇文章主要為大家詳細(xì)介紹了如何利用Qt實(shí)現(xiàn)數(shù)據(jù)庫(kù)數(shù)據(jù)分組導(dǎo)出,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定參考價(jià)值,需要的可以了解一下2022-06-06