define

define是在編譯「前」就進行前置處理,沒辦法debug。

flowchart LR
    程式碼 -- 前置處理 --> 編譯

define 宣告常數

在main()主程式以前,設定常數名與值,後面(尾部)沒有分號;
語法

#define 常數名 值
int main() {
  return 0;
}
1
2
3
4
5
#define PI 3.14
int main() {
  cout << PI << endl; 
  return 0;
}

無法修改define

以下程式碼會編譯錯誤,常數不可再被修改。

1
2
3
4
5
6
#define PI 3.14
int main() {
  PI = 2.55;  // 編譯錯誤
  cout << PI << endl;
  return 0;
}

define取代

編譯的時候,編譯器把以下的值取代常數名,跟內嵌函式是一樣的。
define只是把值取代常數名。

1
#define 常數名 值

以下將”ABCDEFaaaaaa”取代MSG

1
2
3
4
5
#define MSG "ABCDEFaaaaaa"
int main() {
  cout << MSG << endl;
  return 0;
}
ABCDEFaaaaaa

把MSG常數的值改成endl;斷行與分號,以下程式碼編譯不會出錯。

1
2
3
4
5
6
#define MSG endl;
int main() {
  // 注意,以下結尾沒有分號
  cout << MSG
  return 0;
}

結果只會出現一個斷行

define取代與運算

以下的運算結果為10,define是一個取代的過程。

  1. B 變成 1 + 3
  2. C 變成 1 / 1 + 3 * 3
1
2
3
4
5
6
7
#define A 1
#define B A + 3
#define C A / B * 3
int main() {
  printf("%d\n", C);
  return 0;
}
10

加上括號

取代過程如下:

  1. B 變成 (1 + 3)
  2. C 變成 1 / (1 + 3) * 3
  3. C 變成 1 / 4 * 3
1
2
3
4
5
6
7
#define A 1
#define B (A + 3)
#define C A / B * 3
int main() {
  printf("%.2f\n", C);
  return 0;
}
0.0

整數與浮點數

但為何以上的結果是0.0呢?
原因是1 / 4是整數相除,整數會無條件去掉小數點以後的數字,就會變成0。
改成1.0 / 4,就會把整個運算式變成double運算,小數點就會被留下來。

1
2
3
4
5
6
7
#define A 1.0
#define B (A + 3)
#define C A / B * 3
int main() {
  printf("%.2f\n", C);
  return 0;
}
0.75

undef清除常數

undef可以清除已宣告的常數。

1
2
#define PI 3.14159
#undef PI

define 只有常數名沒有值

定義常數名,並不是一定要有值。

1
#define 常數名

例:

1
#define DEBUG

ifdef

判斷是否有定義常數名。

1
2
3
4
5
6
7
8
9
#define DEBUG
int main() {
#ifdef DEBUG // 若有定義DEBUG
  printf("測試測試\n");
#else  // 若沒有定義DEBUG
  printf("不是測試\n");
#endif
  return 0;
}
測試測試

加上undef清除常數。

1
2
3
4
5
6
7
8
9
10
#define DEBUG
#undef DEBUG
int main() {
#ifdef DEBUG // 若有定義DEBUG
  printf("測試測試\n");
#else  // 若沒有定義DEBUG
  printf("不是測試\n");
#endif
  return 0;
}
不是測試

如果沒使用undef在沒有值的常數名,即便下一次編譯時,仍會殘存上一次DEBUG的常數名,就不會執行else的部分。(也有可能是我使用xcode編譯器的問題。)

1
2
3
4
5
6
7
8
int main() {
#ifdef DEBUG // 若有定義DEBUG
  printf("測試測試\n");
#else  // 若沒有定義DEBUG
  printf("不是測試\n");
#endif
  return 0;
}
測試測試

ifndef

若沒有define

1
2
3
4
5
6
7
8
#define DEBUG
#undef DEBUG
int main() {
#ifndef DEBUG
  printf("不是測試\n");
#endif
  return 0;
}
不是測試

以下的程式碼功能跟pragma once一樣,只會被include一次

1
2
3
4
5
6
7
8
9
using namespace std;
#ifndef __CICI__H  // 若沒有定義CICI__H
#define __CICI__H  // 定義它
#include "cici.h"  // 匯入cici.h的內容
#endif
int main() {
  hi();
  return 0;
}
Hello! Cici!

cici.h的內容如下:

1
2
3
4
5
#include <iostream>
using namespace std;
void hi() {
  cout << "Hello! Cici!" << endl;
}

C++提供的前置指令

__cplusplus ,可以辯別是c++還c

檔名 : __FILE__

函式名 : __Function__

程式碼行號 : __LINE__

編譯日期: __DATE__

編譯時間: __TIME__

1
2
3
4
5
6
7
8
9
10
int main() {
  cout << "__cplusplus = " << __cplusplus << endl;
  cout << "__FILE__ = " << __FILE__ << endl;
  cout << "__FUNCTION__ = " << __FUNCTION__ << endl;
  cout << "__LINE__ = " << __LINE__ << endl;
  cout << "__DATE__ = " << __DATE__ << endl;
  cout << "__TIME__ = " << __TIME__ << endl;
  cout << "__TIMESTAMP__ = " << __TIMESTAMP__ << endl;
  return 0;
}
__cplusplus = 201402
__FILE__ = /Users/cici/projects/lsn11/lsn11/main.cpp
__FUNCTION__ = main
__LINE__ = 20
__DATE__ = Jan 13 2025
__TIME__ = 13:41:38
__TIMESTAMP__ = Mon Jan 13 13:41:36 2025

判斷作業系統

Linux : __linux__

Windows : _WIN32

1
2
3
4
5
6
7
8
int main() {
#ifdef _WIN32  // 判斷是不是windows
  cout << "這是windows" << endl;
#else
  cout << "這不是windows" << endl;
#endif
  return 0;
}
這不是windows

不同作業系統,定義型別

在windows中,long是4byte(32bit),long long是8byte(64bit)

在linux中,long是8byte(64bit),二者的long的bit不同。

以下範例自行定義64bit的整數型別,int64,根據判斷作業系統,採用不同的long,但型別的儲存大小都是8byte(64bit)。

1
2
3
4
5
6
7
8
9
10
11
int main() {
#ifdef _WIN32 //判斷是不是windows
  cout << "這是windows" << endl;
  typedef long long int64;
#else
  cout << "這不是windows" << endl;
  typedef long int64;
#endif
  int64 val = 100;
  cout << "val = " << val << endl;
  return 0;
這不是windows
val = 100

results matching ""

    No results matching ""