C/C++ 早期用 0 或 NULL 表示空指針。但 NULL 定義不統一:
0 (int)(void*)0C 語言中 void* 隱式轉換為任意指針類型,故 (void*)0 無傷大雅。但 C++ 嚴禁隱式 void* 轉換,導致重載決議錯誤:
void f(int); // #1 void f(int*); // #2 f(NULL); // 調用 #1 (NULL=0) 而非 #2!類型安全受損
nullptr_t nullptr; // 關鍵字,類型為 std::nullptr_t // 特性: // 1. 隱式轉換為任意指針類型、指向成員指針 // 2. 不隱式轉換為整數類型(包括 bool 需顯式) // 3. sizeof(nullptr) == sizeof(void*)
#include <iostream>
using namespace std;
void f(int) { cout << "f(int)\n"; }
void f(int*) { cout << "f(int*)\n"; }
int main() {
f(0); // f(int)
f(nullptr); // f(int*) ✅ 正確選擇指針重載
f(NULL); // 視 NULL 定義而定,不可靠
int* p = nullptr; // 類型安全初始化
if (!p) cout << "空指針\n"; // 隱式轉 bool 允許
// int x = nullptr; // ❌ 編譯錯誤:不能轉為 int
return 0;
}
void* pv = &i;*pv ❌ 編譯錯誤(無類型信息)pv + 1 ❌(未知大小)static_cast(pv) // 1. 泛型容器/回調上下文
void callback(void* ctx) {
MyData* data = static_cast(ctx);
data->process();
}
// 2. C 風格 API 交互 (如 pthread_create)
void* thread_func(void* arg) { ... }
// 3. 內存分配器返回類型
void* malloc(size_t size);
void free(void* ptr);
| 操作 | nullptr | void* |
|---|---|---|
| 賦值給 T* | ✅ 隱式 | ✅ 隱式 (C) / ❌ 顯式 (C++) |
| 賦值給整數 | ❌ 編譯錯誤 | ❌ 無意義 |
| 解引用 | ❌ 無意義 | ❌ 編譯錯誤 |
| 算術運算 | ❌ | ❌ |
| sizeof | sizeof(void*) | sizeof(void*) |
std::any、std::variant、基類指針static_cast 封裝,內部不用 void*unique_ptr, shared_ptr) 默認構造即為空,無需手動置 nullptrnullptr 解決了 C++ 歷史遺留的類型安全漏洞,是現代 C++ 代碼的標準配置。void* 是 C 時代產物,現代 C++ 應將其限制在與 C 交互的薄薄邊界層。理解兩者區別,是寫出健壯、可維護 C++ 代碼的基礎。