網站首頁 編程語言 正文
一、基本概念
- 條件編譯的行為類似于 C 語言中的 if...else...
- 編譯是預編譯指示命令,用于控制是否編譯某段代碼
下面看一段簡單的條件編譯的代碼:
#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;
}
下面為輸出結果:
可以輸入gcc -E Test.c -o file.i 命令,看看預編譯階段發生了什么,下面是部分輸出結果:
# 2 "Test.c" 2
int main()
{
const char* s;
s = "This is first printf...\n";
printf("%s", s);
return 0;
}
可以看到宏定義和條件編譯都沒有了,由相應內容取而代之。
二、條件編譯的本質
預編譯器根據條件編譯指令有選擇的刪除代碼
編譯器不知道代碼分支的存在
if...else... 語句在運行期進行分支判斷
條件編譯指令在預編譯期進行分支判斷
可以通過命令行定義宏
- gcc -Dmacro=value file.c
- gcc -Dmacro file.c
下面看一個通過命令行定義宏的代碼:
#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,輸出結果如下:
三、#include 的本質
- #include 的本質是將已經存在的文件內容嵌入到當前文件中
- #include 的間接包含同樣會產生嵌入文件內容的操作
這就出現一個問題,間接包含同一個頭文件是否會產生編譯錯誤?
下面就來通過一段代碼深入探究:
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;
}
編譯后編譯器報錯,global 重定義:
為什么 global 會重定義呢?下面開始單步編譯,輸入gcc -E test.c -o test.i,輸出部分結果如下:
# 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 里面的東西復制進 test.c,由于 test.h 里面有一個 include "global.h",就把int global = 10; 復制過來,然后復制
const char* NAME = "test.h";
char* hello_world()
{undefined
return "hello world!\n";
}
在然后由于test.c 里面又定義一個#include "global.h",又把int global = 10; 復制過來,造成了重復定義。
條件編譯可以解決頭文件重復包含的編譯錯誤
#ifndef _HEADER_FILE_H_
#define _HEADER_FILE_H_
//source code
#endif
如果沒有定義 header_file.h,則定義,且執行里面的代碼;否則,如果定義了,里面的代碼就不會執行。
所以上述代碼中可以這么改:
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
這樣編譯就能通過了
四、條件編譯的意義
條件編譯使得我們可以按不同的條件編譯不同的代碼段,因而可以產生不同的目標代碼
#if...#else...#endif 被預編譯器處理,而 if...else... 語句被編譯器處理,必然被編譯進目標代碼
實際工程中條件編譯主要用于以下兩種情況:
- 不同的產品線共用一份代碼
- 區分編譯產品的調試版和發布版
下面看一段產品線區分及調試代碼:
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 是指產品是調試版還是發布版,調試版為 1,發布版為 0, 宏 HIGH指的是產品是高端產品還是低端產品,高端產品為 1,低端產品為 0
如果我們想測試調試版的高端產品,令 DEBUG 為 1,HIGH為 0 即可:
同理,我們想測試發布版的低端產品,令 DEBUG 為 0,HIGH為 0 即可:
五、小結
- 通過編譯器命令行能夠定義預處理器使用的宏
- 條件編譯可以避免重復包含頭同一個頭文件
- 條件編譯是在I程開發中可以區別不同產品線的代碼
- 條件編譯可以定義產品的發布版和調試版
原文鏈接:https://blog.csdn.net/weixin_43129713/article/details/123474028
相關推薦
- 2022-07-22 EasyExcel導出Excel 通過 RGB 設置 表頭顏色
- 2022-03-18 docker?創建容器時指定容器ip的實現示例_docker
- 2021-12-02 深入了解c語言的循環語句_C 語言
- 2022-03-27 C++命名空間和缺省參數介紹_C 語言
- 2022-10-12 常見Android編譯優化問題梳理總結_Android
- 2022-08-19 python循環之彩色圓環實現示例_python
- 2022-04-08 pytorch?plt.savefig()的用法及保存路徑_python
- 2022-06-17 如何使用Python?VTK繪制線條_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支