在 C/C++ 程式設計中,sizeof 與 strlen 是兩個極易混淆卻又截然不同的工具。前者是編譯期運算子,後者是執行期函式;前者計算「類型或變數佔用的記憶體位元組數」,後者計算「C 風格字串的可見字元長度」。本文將從定義、評估時機、參數類型、回傳值語意、典型陷阱與最佳實踐六個維度,為您徹底釐清兩者的差異。
| 特性 | sizeof | strlen |
|---|---|---|
| 性質 | 編譯期運算子(關鍵字) | 執行期函式( |
| 參數 | 型別名稱 或 表達式(不評估副作用) | const char*(以 null 結尾的字串指標) |
| 回傳型別 | size_t(無號整數) | size_t |
| 計算內容 | 物件/型別佔用的位元組總數(含 padding) | 字串中第一個 '\0' 前的字元數(不含結尾 null) |
| 陣列退化 | 不退化,能正確取得整個陣列大小 | 退化為指標,只能取得指標大小 |
| 動態記憶體 | 回傳指標變數本身大小(4/8 位元組) | 正確計算字串長度(前提是合法 C 字串) |
int arr[10];
printf("%zu\n", sizeof(arr)); // 40 (10 * sizeof(int))
printf("%zu\n", sizeof(int)); // 4
printf("%zu\n", sizeof(arr + 0)); // 8 (指標大小,陣列退化)
struct Align { char c; int i; }; // 因對齊通常佔 8 位元組
printf("%zu\n", sizeof(Align)); // 8
sizeof(func()) 不會呼叫 func(),僅根據回傳型別計算大小。sizeof(double)。sizeof(struct) ≥ 成員大小總和。char str[] = "Hello";
printf("%zu\n", strlen(str)); // 5
printf("%zu\n", sizeof(str)); // 6 (含結尾 '\0')
char *p = malloc(100);
strcpy(p, "World");
printf("%zu\n", strlen(p)); // 5
printf("%zu\n", sizeof(p)); // 8 (64-bit 指標大小)
'\0',行為未定義(可能崩潰或讀取垃圾資料)。wchar_t*、std::string 或非字串緩衝區。void bad_print_size(int arr[]) {
// 這裡 arr 實際是 int*,sizeof 回傳指標大小
printf("Size in func: %zu\n", sizeof(arr)); // 8 (64-bit)
}
int main() {
int a[10];
printf("Size in main: %zu\n", sizeof(a)); // 40
bad_print_size(a);
}
解法:改用模板傳遞陣列參考 template<size_t N> void f(int (&)[N]),或額外傳遞長度參數,或改用 std::vector/std::array。
struct Foo { char c; double d; }; // 通常 16 位元組 (1+7 padding+8)
printf("%zu\n", sizeof(Foo)); // 16,而非 9
使用 #pragma pack 或屬性 __attribute__((packed)) 可壓縮結構體,但可能影響存取效能或觸發對齊錯誤(視架構而定)。
int data[5] = {1,2,3,4,5};
// 錯誤!data 不是以 '\0' 結尾的字串
// size_t len = strlen((char*)data); // 未定義行為
std::string、std::vector、std::array 內建 .size(),型別安全且不退化。sizeof 搭配 static_assert 驗證佈局。std::string::length() 或 std::strlen(僅限 C 風格字串介接時)。new/malloc 易導致 sizeof 誤用,改用智慧指標與容器。sizeof 是編譯期的「靜態藍圖」,告訴你類型佔多少位元組;strlen 是執行期的「動態卷尺」,量測以 null 結尾的字串有多少可見字元。牢記「sizeof 看型別,strlen 看內容」,並善用現代 C++ 容器,即可徹底避開這對經典易混淆概念的坑。