首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言 sizeof 與 strlen 徹底講解:編譯期 vs 運行期、指針與數組、結構體對齊陷阱

     編輯:關於C語言

核心區別一句話

sizeof 是編譯期運算符,計算類型/對象佔用的存儲字節數;strlen 是運行期庫函數,計算字符串的可見字符長度 (不含 '\0')。

基本對比表

特性sizeofstrlen
性質運算符 (關鍵字)庫函數 (<string.h>)
計算時機**編譯期** (常量表達式)**運行期** (遍歷內存)
參數類型名 (需括號) / 表達式 (可無括號)const char* (以 '\0' 結尾的字符串)
返回值佔用字節數 (size_t)字符個數 (size_t),不含結束符
適用對象任意類型/變量/表達式僅 C 風格字符串
數組參數退化為指針時**只能得指針大小**正常工作 (接收指針)

經典代碼驗證

#include 
#include 

void func(char arr[]) { // 參數退化為 char*
    printf("sizeof(arr) in func = %zu\n", sizeof(arr)); // 4/8 (指針大小)
}

int main() {
    int *p = NULL;
    int a[10] = {0};
    char b[] = "hello"; // 包含結束符,長度 6

    printf("sizeof(p) = %zu\n", sizeof(p));     // 4/8 (指針大小)
    printf("sizeof(*p) = %zu\n", sizeof(*p));   // sizeof(int) = 4
    printf("strlen(b) = %zu\n", strlen(b));     // 5 (不含 '\0')
    
    func(b); // sizeof(arr) = 4/8
    
    printf("sizeof(a) = %zu\n", sizeof(a));    // 40 (10 * 4)
    printf("sizeof(b) = %zu\n", sizeof(b));    // 6 (含 '\0')
    
    return 0;
}

指針 vs 靜態數組 — sizeof 陷阱

  • 所有指針變量 sizeof 相同 (32位=4, 64位=8),與指向類型無關。
  • sizeof(*p) 等價於 sizeof(指向類型)。
  • 靜態數組 (定義處) sizeof = 整個數組大小;作為函數參數時退化為指針,sizeof 變為指針大小。
  • 字符串字面量 "hello" 是長度 6 的 const char[6],sizeof("hello") == 6。

結構體/聯合體 sizeof — 對齊原則詳解

兩大核心原則

  1. 整體大小 = 最大成員大小的整數倍 (結構體尾部填充)。
  2. 成員偏移量 = 自身大小的整數倍 (內存對齊),不足則插入填充字節。

實例演示

struct A {
    char c;    // 偏移 0, 大小 1
    // 填充 3 字節 (對齊 int 4 字節)
    int i;     // 偏移 4, 大小 4
    // 結構體大小目前 8,最大成員 4,8 是 4 的倍數 → 無尾部填充
}; // sizeof(A) = 8

struct B {
    int i;     // 偏移 0, 大小 4
    char c;    // 偏移 4, 大小 1
    // 尾部填充 3 字節 → 整體 8 (4 的倍數)
}; // sizeof(B) = 8

struct C {
    char c1;   // 0
    char c2;   // 1
    short s;   // 2 (short 對齊 2)
    int i;     // 4 (int 對齊 4)
}; // sizeof(C) = 8

// 數組在結構體中按元素逐個對齊,非整體
struct D {
    char c;
    int arr[2]; // c偏移0, 填充3, arr[0]偏移4, arr[1]偏移8
}; // sizeof(D) = 12

聯合體 — 共享內存,大小 = 最大成員大小 (向上對齊)

union U {
    int i;      // 4
    char c[10]; // 10
    double d;   // 8
}; // sizeof(U) = 16 (max=10, 對齊 max_align_t 通常 8/16 → 16)

#pragma pack 控制對齊

#pragma pack(1) // 1 字節對齊 (無填充)
struct Packed { char c; int i; }; // sizeof = 5
#pragma pack()  // 恢復默認對齊

**慎用**:可能導致非對齊訪問性能下降或硬件異常 (ARM Cortex-M 等)。

sizeof 寫法規範

  • 類型名必須加括號:sizeof(int)、sizeof(struct A)。
  • 變量/表達式可不加括號:sizeof a、sizeof a + b (等價 sizeof(a) + b)。
  • 建議統一加括號:sizeof(a)、sizeof(int),避免歧義,增強可讀性。

避坑檢查清單

  1. ❌ strlen 用於非 '\0' 結尾內存 → 野指針越界讀取,崩潰/數據洩露。
  2. ❌ 函數參數數組用 sizeof 計算元素個數 → 得指針大小。**必須額外傳長度**。
  3. ❌ 結構體大小假設 = 成員大小之和 → 忽略填充字節。**實測 sizeof**。
  4. ❌ sizeof(ptr) 以為是指向內存大小 → 實為指針自身大小。
  5. ✅ 字符串長度用 strlen,緩衝區容量用 sizeof(buf) (僅定義處)。
  6. ✅ 結構體傳參傳指針,內部用 sizeof(*ptr) 獲取真實大小。
  7. ✅ 跨平台代碼用 offsetof (stddef.h) 計算成員偏移,配合靜態斷言驗證佈局。

總結

場景正確用法錯誤示例
字符串可見長度strlen(str)sizeof(str) (若 str 是指針/參數)
緩衝區字節容量sizeof(buf) (定義處)strlen(buf) (未初始化/含 '\0' 中間)
結構體實例大小sizeof(obj)手動加和成員大小
指向類型大小sizeof(*ptr)sizeof(ptr)
函數參數數組長度額外參數傳 lensizeof(arr) 在函數內

搞清 sizeof (編譯期存儲大小) 與 strlen (運行期字符長度) 的本質區別,掌握指針退化、結構體對齊、聯合體共享內存規則,是 C 語言內存管理與接口設計的核心基本功。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved