條件編譯:同一份代碼,產生不同的產品
基本概念:條件編譯的行爲類似於C語言中的if...else...
條件編譯是預編譯指令命令,用於控制是否編譯某段代碼。
#include <stdio.h>
#define C 1
int main()
{
#if( 1 == C )
printf("this is first printf...\n");
#else
printf("this is second printf...\n");
#endif
return 0;
}
單步編譯後發現:
int main()
{
printf("this is first printf...\n");
return 0;
}
預處理器是對代碼進行調整和文本替換,在這個階段,使用宏定義就能對代碼進行刪除和選擇。
條件編譯只是用來指示預編譯器保留什麼代碼,刪除什麼代碼。
通過宏來實現上述操作。
條件編譯的本質:
預編譯器根據條件編譯指令有選擇的刪除代碼;
編譯器不知道代碼分支的存在;
if...else...語句在運行期進行分支判斷(與條件編譯的本質區別)
條件編譯指令在預編譯器進行分支判斷;
可以通過命令行定義宏。
gcc -Dmacro = value file.c
gcc -Dmacro = file.c
對於上面代碼,可是使用命令行進行控制:
~/will$ gcc -DC=1 test.c
~/will$ ./a.out
this is first printf...
~/will$
或者這樣使用命令行進行控制:
#include <stdio.h>
int main()
{
#ifdef C //更改
printf("this is first printf...\n");
#else
printf("this is second printf...\n");
#endif
return 0;
}
~/will$ gcc -DC test.c
~/will$ ./a.out
this is first printf...
~/will$
單步編譯查看代碼:
delphi@delphi-vm:~/will$ gcc -DC -E test.c -o test.i //定義C
delphi@delphi-vm:~/will$
int main()
{
printf("this is first printf...\n"); //test.i
return 0;
}
delphi@delphi-vm:~/will$ gcc -E test.c -o test.i //不定義C
delphi@delphi-vm:~/will$
int main()
{
printf("this is second printf...\n");
return 0;
}
#include 的本質 //是和預處理器相關的指令
#include的本質是將已經存在的文件嵌入到當前文件中
#include的間接包含同樣會產生嵌入文件內容的操作
問題:間接包含同一個頭文件是否會出現編譯錯誤?
global.h <-- test.h <-- test.c -->global.h
會。在預編譯階段將#include包含的文件進行展開,重複包含將會出現重複定義。redefination。預編譯不會報錯,但是編譯會出現錯誤。重複定義。
如何避免在大的工程中避免這種情況呢?
#ifndef statement //如果已經定義 則在預處理階段直接刪除接下來的代碼
#define statement
//...//
#endif
條件編譯可以解決頭文件重複包含的編譯錯誤
示例:
#ifndef _HEADER_FILE_H_
#define _HEADER_FILE_H_
//source code
#endif
條件編譯使得我們可以按照不同的條件編譯不同的代碼段,因而可以產生不同的目標代碼。
#if...#else...#endif被預處理器處理,而if...else...語句被編譯器處理。
實際工程中條件編譯主要用於以下兩種情況:
——不同的產品線共用一份代碼
——區分編譯產品的調試版和發佈版
在這裏需要注意的是,與前面通過命令行定義宏的方式不同,此處是直接在外部定義頭文件包含,通過修改頭文件中宏定義來進行條件編譯,如果想通過命令行的方式進行條件編譯,需要先註釋掉頭文件包含。
~/will$ gcc -DDEBUG=1 -DHIGH=1 22-4.c
~/will$
~/will$ ./a.out
[22-4.c:23] Enter main() ...
This is the high level product!
1. Query Information.
2. Record Information.
3. Delete Information.
4. High Level Query.
5. Mannul Service.
6. Exit.
[22-4.c:39] Exit main() ...
示例代碼:
#include <stdio.h>
//#include <global.h>
#if DEBUG
#define LOG(s) printf("[%s:%d] %s", _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\n");
printf("2\n");
printf("3\n");
#if HIGH
printf("4\n");
printf("5\n");
printf("6\n");
#else
printf("4\n");
#endif
LOG("Exit main()...")
return 0;
}
不同的條件編譯:~/will$ gcc -DDEBUG=1 -DHIGH=1 22-4.c
~/will$ ./a.out
[22-4.c:23] Enter main()...
this is the high level product!
1
2
3
4
5
6
[22-4.c:41] Exit main()...
delphi@delphi-vm:~/will$ gcc 22-4.c
delphi@delphi-vm:~/will$ ./a.out
1
2
3
4
小結:通過編譯器命令行能夠定於預處理器使用的宏
條件編譯可以避免重複包含同一個頭文件
條件編譯在工程開發中可以定義不同產品線的代碼
條件編譯可以定義不同產品的發佈版和調試版