指標長度基礎認知
現代平台:資料指標長度通常一致(32 位元系統 4 bytes、64 位元系統 8 bytes),與指向型態無關。
C 標準:不保證所有型態指標長度相同,但實務上幾乎一致。
函數指標:長度可能不同於資料指標(如 Harvard 架構、分段記憶體模型)。
指標長度測試程式
#include
#include
struct p { int n; float f; };
int main() {
struct p *sptr;
printf("sizeof *char: %zu\n", sizeof(char*));
printf("sizeof *int: %zu\n", sizeof(int*));
printf("sizeof *float: %zu\n", sizeof(float*));
printf("sizeof *double: %zu\n", sizeof(double*));
printf("sizeof *struct: %zu\n", sizeof(sptr));
return 0;
}
典型 64 位元輸出:全部為 8(bytes)
典型 32 位元輸出:全部為 4(bytes)
指標相關預定義類型
| 類型 | 定義於 | 用途 | 特性 |
| size_t | stddef.h | 物件大小、陣列索引、迴圈計數 | 無號,足以容納最大物件大小 |
| ptrdiff_t | stddef.h | 指標差值(指標減法結果) | 有號,可表示負差值 |
| intptr_t | stdint.h (C99) | 儲存指標位址(整數形式) | 有號,足以容納指標 |
| uintptr_t | stdint.h (C99) | 儲存指標位址(無號形式) | 無號,足以容納指標 |
size_t 類型深度解析
本質:機器相關的無號整數型別,大小足以表示記憶體中最大物件位元組數。
32 位元系統:4 bytes(unsigned int)
64 位元系統:8 bytes(unsigned long)
核心用途
sizeof 運算子返回型別
- 記憶體分配函數參數:
malloc(size_t)
- 字串長度:
strlen 返回 size_t
- 陣列索引、迴圈計數器、指標運算
列印格式陷阱
size_t 為無號型別,列印需用正確格式:
- 推薦:
%zu (C99)
- 相容:
%lu (配合 unsigned long 轉型)、%u (32 位元)
- 錯誤:
%d、%ld — 可能導致負數顯示或截斷
範例
size_t s = sizeof(double);
printf("Size: %zu\n", s); // 正確
ptrdiff_t 類型深度解析
本質:有號整數型別,用於儲存同一陣列中兩指標相減的結果。
與 size_t 差異:size_t 為無號(長度非負),ptrdiff_t 為有號(差值可負)。
範例:計算字串長度
#include
#include
#include
int main() {
char str[] = "Hello world!";
char *pstart = str;
char *pend = str + strlen(str);
ptrdiff_t diff = pend - pstart;
printf("Length: %td\n", diff); // %td 為 ptrdiff_t 格式 (C99)
return 0;
}
intptr_t / uintptr_t:指標與整數互轉
用途:將指標位址儲存為整數,進行整數運算後轉回指標。
保證:(void*)(uintptr_t)ptr == ptr(往返轉換保值)。
應用場景
- 指標標記(利用低位元組對齊位存狀態)
- 指標哈希、比較、儲存於整數容器
- 與硬體介面交互(暫存器映射)
- 偵錯器、序列化工具處理指標值
範例:指標標記
#include
void *ptr = malloc(100);
// 利用對齊特性(假設 8 位元組對齊,低 3 位為 0)
uintptr_t marked = (uintptr_t)ptr | 1; // 設標記位
// 使用時清除標記
void *original = (void*)(marked & ~1);
指標運算規則
- 指標 + 整數:按指向型態大小縮放,
ptr + n 移動 n * sizeof(*ptr) 位元組
- 指標 - 指標:同一陣列內,返回元素個數差(
ptrdiff_t)
- 指標比較:同一陣列/物件內比較位址大小
- 指標 - 整數:反向移動
- 禁止:指標 + 指標、指標 * 整數、指標 / 整數、指標 % 整數
可移植性最佳實踐
- 使用
size_t 表示大小、索引、計數
- 指標差值用
ptrdiff_t
- 指標轉整數用
uintptr_t/intptr_t
- 避免假設指標長度(
sizeof(void*) == sizeof(int) 在 64 位元錯誤)
- 避免指標與
int/long 直接轉換,用標準類型
printf 格式:%p 印指標、%zu 印 size_t、%td 印 ptrdiff_t
總結
- 資料指標長度通常與平台位元數一致(32/64 bits),函數指標可能不同
size_t:大小/索引/計數首選,無號,%zu
ptrdiff_t:指標差值,有號,%td
intptr_t/uintptr_t:指標↔整數安全轉換
- 善用標準類型而非假設長度,編寫可移植 32/64 位元程式碼
- 上一篇文章: C語言位域有號無號測試:有號位域負值陷阱實測
- 下一篇文章: Objective-C 與 Core Foundation 對象互轉內存管理全攻略:ARC 與非 ARC 環境下的最佳實踐
Copyright ©
程式碼之家 All Rights Reserved