# 前置處理器 ###### tags: `Competitive Programming Note` 本文已停止更新,新版請至 [WiwiHo 的競程筆記](https://cp.wiwiho.me/) 大家應該都看過這些東西: ```cpp= #define test 123 #include<iostream> ``` 這種以 `#` 為開頭的程式碼稱為**前置處理器**,大家應該都知道 C++ 的程式碼需要先經過編譯才能執行,而前置處理器是在編譯之前就執行的,經過前置處理器處理完後的程式碼才會被編譯。 舉例來說,`#include` 會在編譯前將指定檔案裡的文字完全複製貼上到你 include 的那個地方,它可以用在任何地方,例如: 你開了一個檔案叫做 `hello.txt`,內容只有 `"hello"`,然後你在同目錄有另一個檔案 `test.cpp`,內容是: ```cpp= #include<iostream> using namespace std; int main(){ cout << #include "hello.txt" << "\n"; return 0; } ``` 那麼會輸出 `hello`,在編譯之前,`#include "hello.txt"` 這一行就會被替換成 `"hello"`。 還有一個常見的前置處理器是 `#define`,結構是 `#define 識別碼(identifier) 替換字串`,也被稱為「巨集」或「宏」,英文是 macro,有些人可能會說這是「常數」,然後你就會開始懷疑它跟 `const` 的差別,其實 `#define` 並不是在宣告一個常數,而是它會把整份程式碼中的一段特定文字替換,例如: ```cpp= #include<iosteam> #define hello "hello" using namespace std; int main(){ cout << hello << "\n"; return 0; } ``` 在編譯之前,`hello` 就會被替換成 `"hello"`,接著才進行編譯,所以輸出會是 `hello`。它也有函式的用法: ```cpp= #inlcude<iosteam> #define say(a) cout << a << "\n" using namespace std; int main(){ say("hello"); return 0; } ``` 這樣會輸出 `hello`,在編譯前,`say("hello")` 會被替換成 `cout << a << "\n"`。 要特別注意的一點是,因為這是把文字原封不動貼上,所以 `#define` 替換的部分**不會**先做運算,而是在執行期按照前置處理器處理完的程式碼運算,例如: ```cpp= #include<iostream> #define plus(a, b) a + b using namespace std; int main(){ cout << (plus(1, 2) * 3) << "\n"; return 0; } ``` 這樣的結果並不是 `9`,而是 `7`,因為替換完後的程式碼會是 `1 + 2 * 3`,`2 * 3` 會先被計算。所以我建議用個括號把它包起來。 以上是 `#define` 的「巨集」用法,而 `#define` 還有另一個功用,前置處理器也有 if 的語法,它們都和 `#define` 有關。 最單純的是 `#if`、`#elif`、`#else`、`#endif`,用法例如: ```cpp= #include<iostream> #define A 3 using namespace std; int main(){ #if A == 3 cout << "test\n"; #elif A == 2 cout << "hello\n"; #else cout << "QQ\n"; #endif return 0; } ``` 這就像是一般的 if 控制語法,而是以 `#endif` 結束區塊,要巢狀結構也可以。如果判斷結果是 `true`,那個區塊才會被編譯,上述的範例中,只有 `A==3` 這個判斷會是 `true`,因此只有第 7 行會被編譯,第 9 和 11 行不會。前置處理器的判斷只能判 `#define` 定義的東西,幾乎所有運算子都可以用。如果把第 2 行改成 `#define A 2`,那被編譯的就會是第 9 行,如果 `A` 不是 `2` 也不是 `3`,那被編譯的就會是第 11 行。 除了可以判斷值之外,也可以判斷一個識別碼有無被定義,用 `defined(識別碼)` 就可以得到指定的識別碼有沒有 define 過,例如: ```cpp= #include<iostream> #define A using namespace std; int main(){ #if defined(A) cout << "test\n"; #endif #if defined(B) cout << "hi\n"; #endif return 0; } ``` 第 7 行會被編譯,而第 10 行不會。`#if defined(A)` 可以簡寫為 `#ifdef A`,而 `#if !defined(A)` 可以簡寫為 `#ifndef A`。 這通常會用來避免標頭檔被重複 include,至於競程上,如果你打了一大段測試用的程式碼,覺得要在 submit 前註解掉、WA 了又要取消註解很麻煩,那就可以用個 `#ifdef` 來處理,會方便許多。
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up