Download presentation
Presentation is loading. Please wait.
Published byJustus Dunkle Modified 6年之前
1
前處理指令可以要求前處理器 (preprocessor) 在程式編譯之前,先進行加入其它檔案的內容、文字取代以及選擇性編譯等工作。
Chap 11 前處理指令 前處理指令可以要求前處理器 (preprocessor) 在程式編譯之前,先進行加入其它檔案的內容、文字取代以及選擇性編譯等工作。
2
前處理指令 11.1 前處理器 11.2 使用 #define進行文字取代 11.3 使用 #define設定巨集指令 11.4 條件式編譯 11.5 其他與編譯器有關的前處理指令
3
前處理指令 #include 前處理指令不是C++ 敘述,不用分號「;」做結尾。例如:
#include <iomanip> 與 #include 配合的檔案名稱有兩種語法。 例如: #include “Commom.h” 附錄 C中列出了C++ 標準程式庫裏面常用的標檔。 可以將檔案的詳細路徑寫在雙引號內。 例如: #include “c:\C++Test\Commom.h”
4
以 #define 開頭的前處理指令有四種功能:
宣告某一個代號的值。 產生符號常數 (symbolic constant)。 產生巨集 (macro)。 宣告某一個代號已經被設定。
5
除了包括在字串 (string) 之內的文字以外,所有吻合的文字,都將被代號直接取代。例如:
以 #define開頭的前處理指令 #define 代號 被取代文字 除了包括在字串 (string) 之內的文字以外,所有吻合的文字,都將被代號直接取代。例如: #define and && #define or || #define not !
6
範例程式LogicTest.cpp // 前處理指令 #define and && #define or || #define not ! #include <iostream> using namespace std;
7
cout << "((t1 > 0.8) and (t2 <0.9) or (t1>0.2))= "
// 主程式 int main() { float t1,t2; t1=0.5; t2=t1*0.2; cout << "((t1 > 0.8) and (t2 <0.9) or (t1>0.2))= " << ((t1 > 0.8) and (t2 <0.9) or (t1>0.2)) << endl; cout << " not(t1 > t2) = " << not(t1 > t2) << endl; return 0; }
8
程式執行結果 ((t1> 0.8) and (t2 <0.9) or (t1>0.2))= 1 not(t1 > t2) = 0
9
宣告符號常數(symbolic constant)
符號常數因為直接取代程式內的代號,本身並不佔用記憶空間,而每個常數在定義時即擁有自己的記憶空間。 #define RAND_MAX 0x7FFFU #define PI 比較好的做法是使用常數。例如: const double PI = ; const double PI = 2.0*asin(1.0);
10
前處理指令內禁用的代號 代 號 意 義 --LINE-- 行號 --FILE-- 檔名 --DATE-- 編譯日期 --TIME--
代 號 意 義 --LINE-- 行號 --FILE-- 檔名 --DATE-- 編譯日期 --TIME-- 編譯時間
11
行號不會加在程式裹面,程式的檔案名稱也沒有真的被更動,這個指令的最大用途在於大型檔案的除錯 (debugging)。
以 #line開頭的前處理指令 行號不會加在程式裹面,程式的檔案名稱也沒有真的被更動,這個指令的最大用途在於大型檔案的除錯 (debugging)。 #line 120 #line 120 "Test File.cpp"
12
範例程式Reserved.cpp 使用保留代號
#include <iostream> using namespace std; // ---- 主程式 int main() { cout << "行號 : " << --LINE-- << endl; cout << "檔名 : " << --FILE-- << endl; cout << "編譯日期: " << --DATE-- << endl; cout << "編譯時間: " << --TIME-- << endl;
13
#line 120 "Test File.cpp" cout << "執行 #line 120 \"Test File.cpp\"之後: " << endl; cout << "行號 : " << --LINE-- << endl; cout << "檔名 : " << --FILE-- << endl; return 0; }
14
程式執行結果 行號 : 7 檔名 : Reserved.cpp 編譯日期 : Sep 13 2004 編譯時間 : 09:30:38
行號 : 7 檔名 : Reserved.cpp 編譯日期 : Sep 編譯時間 : 09:30:38 執行 #line 120 "Test File.cpp"之後: 行號 : 122 檔名 : Test File.cpp
15
使用 #define 設定巨集(macro)
巨集指令的參數直接取代巨集本體部份的代號。例如: #define MAX(x,y) ((x) > (y) ? (x) : (y)) 它的功能相當於下列的inline樣版函數: template <class T> inline const T& MAX(const T& x, const T& y) {return x > y ? x : y;}
16
巨集本體部份的代號 在執行時會被引數直接取代
如果設定了一個叫做PRODUCT的巨集: #define PRODUCT(x,y) (x * y) 則 double F1 = 12.5, F2 = 8.38; cout << PRODUCT(F1+2, F2+6) << endl; 相當於執行: cout << * << endl;
17
PRODUCT巨集和inline樣版函數
#define PRODUCT(x,y) ((x) * (y)) 它的功能相當於下列的inline樣版函數: template <class T> inline const T& PRODUCT(const T& x, const T& y) {return x*y;}
18
將巨集指令的參數名稱直接以字串的型式輸出
只要將巨集本體部份相對於參數的代號前加上「#」即可。 例如: #define ShowValue(x) \ { \ cerr << #x << " 的值是: " << x << end \ } 如果我們在程式中執行下列敘述: double F1= 12.5; ShowValue(F1); 結果: F1的值是: 12.5
19
合併巨集指令的參數 例如,定義一個名叫 Merge的巨集: 如果在程式中執行下列敘述: 可以得到下列結果:
#define Merge(x, y) x##y 如果在程式中執行下列敘述: double F1= 12.5; cout << "執行 Merge(F,1) 的結果是: " << Merge(F,1) << endl; 可以得到下列結果: 執行 Merge(F,1) 的結果是: 12.5
20
範例程式MacroTest.cpp: 建立和使用 MAX、PRODUCT、Merge,和ShowValue四個巨集指令
#include <iostream> using namespace std; // -- 巨集指令 #define MAX(x,y) ((x) > (y) ? (x) : (y)) #define PRODUCT(x,y) ((x) * (y)) #define Merge(x, y) x##y #define ShowValue(x) \ { \ cerr << #x << " 的值是: " << x << endl; \ cerr << "按 Enter 鍵繼續." << endl; \ cin.get(); \ }
21
// ---- 主程式 -------------------------------
int main() { int a = 3, b = 9; double F1= 12.5, F2=8.38; cout << "MAX(a, b) = " << MAX(a, b) << endl; cout << "MAX(F1, F2) = " << MAX(F1, F2) << endl; cout << "PRODUCT(F1, F2) = " << PRODUCT(F1+2, F2+6) << endl; ShowValue(F1); cout << "\n執行 Merge(F,2) 的結果是:" << Merge(F,2) << endl; return 0; }
22
程式執行結果 MAX(a, b) = 9 MAX(F1, F2) = 12.5 PRODUCT(F1, F2) = 208.51
按 Enter 鍵繼續. 執行 Merge(F,2) 的結果是: 8.38
23
條件式編譯(conditional compilation)
可以有選擇性地執行某些前處理指令,或有選擇性地只編譯原始程式碼的某些部份。常用的有下列數種: #ifdef #ifndef #else #endif #if defined() #if !defined() #elif
24
使用 #define設定代號 下列指令設定了代號Mark: #define Mark
25
以前處理指令避免重複加入同一個標頭檔 (1)
以前處理指令避免重複加入同一個標頭檔 (1) 例如:在標頭檔Commom.h內加入: #ifndef Common_h #define Common_h // 標頭檔 Common.h 的主要內容 // 如果 Common_h沒設定過才加入這個部份 #endif 在上式中,「#ifndef Common_h」也可以寫成 #if !defined(Common_h)
26
以前處理指令避免重複加入同一個標頭檔 (2)
以前處理指令避免重複加入同一個標頭檔 (2) 標頭檔Commom.h還可以寫成下列格式: #ifdef Common_h #else #define Common_h // … 標頭檔 Common.h 的主要內容 // … 如果 Common_h沒設定過才加入這個部份 #endif
27
範例程式Common.h 檔案MacroTest.cpp分成Common.h和Macro2.cpp 兩個檔案。 // Common.h #ifndef Common_h #define Common_h #include <iostream> using namespace std;
28
// -- 巨集指令 ---------------------------
#define MAX(x,y) ((x) > (y) ? (x) : (y)) #define PRODUCT(x,y) ((x) * (y)) #define Merge(x, y) x##y #define ShowValue(x) \ { \ cerr << #x << " 的值是: " << x << endl; \ cerr << "按 Enter 鍵繼續." << endl; \ cin.get(); \ } #endif
29
範例程式Macro2.cpp // MacroTest.cpp // Macro2.cpp #include "Common.h"
// ---- 主程式 int main() { int a = 3, b = 9; double F1= 12.5, F2=8.38;
30
cout << "MAX(a, b) = " << MAX(a, b)<< endl;
cout << "MAX(F1, F2) = " << MAX(F1, F2) << endl; cout << "PRODUCT(F1, F2) = " << PRODUCT(F1+2, F2+6) << endl; ShowValue(F1); cout << "\n執行 Merge(F,2) 的結果是: " << Merge(F,2) << endl; return 0; }
31
利用前處理指令插入除錯專用的敘述 藉由 #define 和 #undef前處理指令來做為執行的開關。例如,將巨集Breakpoint以下列的方式包裹起來: #define Debug #if defined(Debug) #define Breakpoint(x) { \ cerr << #x << " 的值是: " << x << endl; \ cerr << "按 Enter 鍵繼續." << endl; \ cin.get(); \ } #else #endif
32
藉由「#if 0」和「#endif」把要暫時忽略不編譯的區域包圍起來。如下列語法所示:
利用前處理指令暫時忽略部份程式 藉由「#if 0」和「#endif」把要暫時忽略不編譯的區域包圍起來。如下列語法所示: // ---- 其它敘述 ---- #if 0 // ---- 暫時不處理的區域 #endif
33
利用assert( ) 協助除錯 標頭檔 <cassert> 提供了函數 assert()。可以使用
#define NDEBUG #undef NDEBUG 做為函數assert()的開關。 assert(i<15); 一旦 I 大於或等於15,就會立即關閉程式,並發出錯誤訊息: Assertion failed: i < 15, file Test.cpp, line 40
34
範例程式Debug.cpp // Debug.cpp #define Debug #if defined(Debug)
#define Breakpoint(x) \ { \ cerr << #x << “ 的值是: “ << x << endl; \ cerr << “按 Enter 鍵繼續.” << endl; \ cin.get(); \ } #else #define Breakpoint(x) #endif #undef NDEBUG
35
#include <iomanip>
#include <iostream> #include <stdlib> #include <cassert> using namespace std; inline double Rand() // 定義 inline 函數 Rand() {return double(rand())/RAND_MAX;}
36
// ---- 主程式 -----------------------------
int main() { srand(int(time(0))); const int Size = 20; double Data[Size]; for (int i=0; i<Size; i++) Data[i]= 10.0*Rand()-5.0; assert(i<Size); } Breakpoint(Data[Size-1]); return 0;
37
程式執行結果 (因為程式會產生亂數,每一次執行結果都不相同。)
Data[Size-1] 的值是: 按Enter鍵繼續。
38
#pragma前處理指令 有某些特殊的前處理指令可以被某些編譯器接受,例如 #pragma warn -nak
39
#error 前處理指令 下列前處理指令: 這個語法相當於下列指令: #ifndef __cplusplus
#error Must use C++ for the type bcd. #endif 這個語法相當於下列指令: cerr << “ Must use C++ for the type bcd.”;
Similar presentations