long i = -1;
if (i < sizeof(i)) { // sizeof 回傳 size_t (無號)
printf("OK\n");
} else {
printf("Error\n"); // 輸出 Error!
}
C 標準「慣用算術轉換」規則:
/* 方法 1:雙方同為有號 */
if ((long)i < (long)sizeof(i))
/* 方法 2:先檢查負數 */
if (i >= 0 && (size_t)i < sizeof(i))
/* 方法 3:用 intptr_t 統一有號指標大小 */
#include
if (i < (intptr_t)sizeof(i))
為了可移植性,**永遠使用 `
| 分類 | 型別範例 | 用途 |
|---|---|---|
| 精確寬度 | `int32_t`, `uint64_t` | 網路協定、檔案格式、硬體暫存器 |
| 最小寬度 | `int_least32_t` | 至少 N bits,編譯器挑最快 |
| 最快最小寬度 | `int_fast32_t` | 至少 N bits 且最快 (通常等於機器字長) |
uint16_t a = 65535, b = 1;
uint32_t sum = a + b; // 32-bit 平台:a,b 提升為 int (16-bit 會提升為 int),結果 65536
// 16-bit 平台:a,b 提升為 unsigned int,結果 0 (溢位)
**結論**:跨平台代碼**不可假設 `int` 寬度**,關鍵運算明確轉型至固定寬度型別。
char c = 128; // 有號 char 視為 -128,無號視為 128
printf("%d\n", c); // x86 GCC 輸出 -128 (預設 signed char)
// ARM 某編譯器輸出 128 (預設 unsigned char)
**強制指定**:signed char / unsigned char,或編譯選項 `-fsigned-char` / `-funsigned-char`。
| 函數 | 行為 | 關鍵點 |
|---|---|---|
| `malloc(size)` | 分配未初始化記憶體 | size=0 行為未定義 (可能返回 NULL 或唯一指標) |
| `calloc(n, size)` | 分配並**歸零** | 自動計算總大小 n*size,避免溢位;適合陣列 |
| `realloc(ptr, new_size)` | 調整大小,可能移動 | 失敗返回 NULL,**原記憶體不釋放**;ptr=NULL 等同 malloc |
| `free(ptr)` | 釋放 | ptr=NULL 安全無操作;釋放後**必須置 NULL** 防雙重釋放 |
void *safe_malloc(size_t n, size_t size) {
if (n == 0 || size == 0) return NULL;
if (n > SIZE_MAX / size) { errno = ENOMEM; return NULL; } // 溢位檢查
void *p = malloc(n * size);
return p;
}
typedef struct {
int *data;
size_t size; // 當前元素數
size_t capacity; // 已分配容量
} IntVec;
bool vec_push(IntVec *v, int val) {
if (v->size == v->capacity) {
size_t new_cap = v->capacity ? v->capacity * 2 : 4;
if (new_cap > SIZE_MAX / sizeof(int)) return false;
int *new_data = realloc(v->data, new_cap * sizeof(int));
if (!new_data) return false;
v->data = new_data;
v->capacity = new_cap;
}
v->data[v->size++] = val;
return true;
}
void vec_free(IntVec *v) {
free(v->data);
v->data = NULL;
v->size = v->capacity = 0;
}
| 錯誤 | 後果 | 修正 |
|---|---|---|
| `free` 後未置 NULL | 野指標、二次釋放崩潰 | `free(p); p = NULL;` |
| `realloc` 失敗未保留舊指標 | 記憶體洩漏 | `new = realloc(p, sz); if (!new) { /* p 仍有效 */ } else p = new;` |
| 釋放非堆記憶體 (堆疊/全域/字面常數) | 未定義行為、崩潰 | 只 `free` 來自 `malloc`/`calloc`/`realloc` 的指標 |
| 跨 DLL 分配/釋放不匹配 | 堆破壞 | 分配者負責釋放,提供 `xxx_free` API |
整數轉換陷阱源於 **C 的隱式轉換規則 + 平台相關型別寬度**;記憶體管理痛點在於 **手動擁有權 + 無 GC**。掌握固定寬度型別、顯式轉型、溢位檢查、RAII 風格封裝、記憶體池、引用計數,能消滅 95% 的整數與記憶體 Bug。下一部分將探討陣列指標轉換、顯式記憶體函數、Interpositioning 與向量化。