| 用法 | 語義 | 示例 |
|---|---|---|
| 函數返回類型 | 函數無返回值 | void foo(void); |
| 函數參數列表 | 函數不接受任何參數 | int bar(void); (C++ 隱式等同 int bar();) |
| 指針類型 | 通用指針,可指向任意對象類型 | void *p = malloc(100); |
void*,無需強轉。
int *pi = malloc(sizeof(int)); void *pv = pi; // 合法,隱式
void* 不能隱式轉換 為其他指針類型,**必須強制轉換**。
int *pi2 = pv; // C: 警告/錯誤 (C++ 錯誤) int *pi3 = (int *)pv; // 正確,顯式強轉
void* 進行指針算術 (pv++, pv + 1),因為「無類型」無法確定步長。
void* 算術,**視為 char* (步長 1 字節)**。-Wpointer-arith 會警告。(char *)pv + offset 或 (uint8_t *)pv + offset。*pv 編譯錯誤,因為無類型無法確定讀取大小。需先轉型。void 不是完整類型,無大小。sizeof(void*) 是指針大小 (4/8 字節)。void *memcpy(void *dest, const void *src, size_t n); void *memset(void *s, int c, size_t n); void *malloc(size_t size); void free(void *ptr); int pthread_create(pthread_t *, const pthread_attr_t *, void *(*start_routine)(void *), void *arg);
設計哲學:內存操作不關心數據類型,只搬運字節;線程入口不關心參數類型,由調用者約定。
typedef void (*Callback)(void *context);
void register_cb(Callback cb, void *ctx); // 庫不關心 ctx 類型
// 使用者
struct MyContext { int id; float value; };
void my_cb(void *ctx) {
struct MyContext *c = (struct MyContext *)ctx; // 約定轉型
printf("id=%d, val=%f\n", c->id, c->value);
}
struct MyContext ctx = {42, 3.14};
register_cb(my_cb, &ctx);
struct Shape { void (*draw)(void *self); };
void draw_circle(void *self) { ... }
void draw_rect(void *self) { ... }
struct Circle { struct Shape base; int r; };
struct Rect { struct Shape base; int w, h; };
void shape_draw(struct Shape *s) { s->draw(s); }
// 使用
struct Circle c = {{draw_circle}, 10};
shape_draw((struct Shape *)&c);
| 場景 | 推薦類型 | 理由 |
|---|---|---|
| 分配原始內存塊 | void * | malloc/calloc/realloc 返回類型 |
| 內存拷貝/設置/比較 | void * / const void * | 標準庫約定,類型無關 |
| 泛型容器節點 | void * | 存儲任意類型指針 |
| 回調上下文 | void * | 解耦庫與業務類型 |
| 函數內部操作具體數據 | 具體類型 * | 類型安全、可讀性、避免重複強轉 |
| 結構體成員指向數據 | 具體類型 * | 語義清晰、編譯器檢查 |
void v; 編譯錯誤。void 不能定義對象。int f() 表示「參數未指定」(舊式),int f(void) 表示「無參數」。**C++ 中兩者等價**。現代 C **必須寫 void**。pv += 4; 非標準。改用 (char*)pv += 4;。void *p = "hello"; int *pi = (int *)p; 違反嚴格別名規則,未定義行為。用 memcpy 或 union 進行類型懲罰。const void * 指向「不可通過此指針修改的數據」,常用於 memcpy src 參數。結合
void*容器與_Generic分發,實現編譯期類型安全的異構容器。總結
void是 C 語言類型系統中的「底類型」占位符,void*是「頂類型」指針 (任意對象指針的超類型)。掌握隱式轉換方向、算術限制、解引用禁令、標準庫約定、回調上下文模式、類型擦除技術,能編寫類型安全、可移植、可擴展的系統級 C 代碼。鐵律:**邊界用 void*,內部用具體類型,轉型點集中封裝,嚴禁隨意強轉**。