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

C 語言 sizeof 運算符深度解析:類型大小、結構體對齊與常見面試陷阱

     編輯:關於C語言

前言

sizeof 是 C/C++ 筆試面試的高頻考點,看似簡單卻暗藏玄機。本文系統梳理 sizeof 的核心規則、基本類型大小、指針與數組的區別、結構體內存對齊規則,並通過實測代碼驗證結論。

sizeof 基礎語法與特性

  • 單目運算符,非函數:sizeof(type) 或 sizeof expression
  • 編譯期計算(動態分配內存/VLA 除外),不產生運行時指令
  • 返回類型:size_t(無符號整數)
  • 含義:對象在內存中佔用的字節數

基本類型大小(32 位系統典型值)

類型大小 (bytes)備註
char / signed char / unsigned char1定義為 1 字節
short / short int2
int432 位系統通常 4 字節
long / long int432 位系統通常 4 字節
long long8C99/C++11
float4IEEE 754 單精度
double8IEEE 754 雙精度
long double12/16實現相關,常為 12 或 16
指針 (T*)432 位系統地址寬度

注意: C 標準僅保證 sizeof(char) == 1 及 sizeof(short) <= sizeof(int) <= sizeof(long),具體大小由實現定義(ABI)。64 位系統下指針與 long 通常為 8 字節。

指針 vs. 數組:經典誤區


char str[] = "ABC"; // 數組,大小 4 (含 '\0')
char* p = str;      // 指針,大小 4 (32位) / 8 (64位)

sizeof(str); // 4 —— 數組類型包含長度信息
sizeof(p);   // 4/8 —— 指針類型只存地址
sizeof(*p);  // 1 —— 解引用得到 char

核心區別: 數組類型編碼了長度,指針類型不包含長度信息。函數參數中數組退化為指針,sizeof 失效。

結構體內存對齊:sizeof 變大的元兇

結構體大小**不等於**成員大小之和,編譯器為了 CPU 訪問效率,會插入填充字節(padding)。

對齊規則

  • 結構體起始地址為其最嚴格對齊要求成員的倍數
  • 每個成員相對結構體起始地址的偏移量必須是其自身大小的倍數(或編譯器指定對齊數)
  • 結構體總大小必須是其最大對齊要求的倍數(尾部填充)

實例對比:成員順序影響大小


// 結構體 A:double(8) + char(1) + int(4)
struct A {
    double d; // offset 0, size 8
    char c;   // offset 8, size 1
    int i;    // offset 12 (需 4 對齊), size 4
}; // 總大小 16 (8+1+3填充+4)

// 結構體 B:char(1) + double(8) + int(4)
struct B {
    char c;   // offset 0, size 1
    double d; // offset 8 (需 8 對齊, 填充 7), size 8
    int i;    // offset 16, size 4
}; // 總大小 24 (1+7填充+8+4+4尾部填充)

結論: 將大類型(double、long long)放在前面,小類型放後面,通常能減少填充,縮小結構體體積。

實測代碼


#include 
#include 

struct Str1 { double d; char c; int i; };
struct Str2 { char c; double d; int i; };

int main() {
    short sa = 10; int a = 10; long la = 10;
    float f = 20; double d = 20; char ch = 'c';
    char str[] = "ABC"; char* p = str;
    struct Str1 s1; struct Str2 s2;

    printf("sizeof(short): %zu\n", sizeof(sa));   // 2
    printf("sizeof(int): %zu\n", sizeof(a));      // 4
    printf("sizeof(long): %zu\n", sizeof(la));    // 4
    printf("sizeof(float): %zu\n", sizeof(f));    // 4
    printf("sizeof(double): %zu\n", sizeof(d));   // 8
    printf("sizeof(char): %zu\n", sizeof(ch));    // 1
    printf("sizeof(str[]): %zu\n", sizeof(str));  // 4
    printf("sizeof(p): %zu\n", sizeof(p));        // 4 (32位)
    printf("sizeof(*p): %zu\n", sizeof(*p));      // 1
    printf("sizeof(Str1): %zu\n", sizeof(s1));    // 16
    printf("sizeof(Str2): %zu\n", sizeof(s2));    // 24
    return 0;
}

常見面試陷阱總結

  1. sizeof(int) vs sizeof(long):32 位系統通常相同,64 位系統 long 可能為 8
  2. 函數參數 void f(int arr[]) 等價於 void f(int* arr),sizeof(arr) 返回指針大小
  3. malloc 返回指針,sizeof(ptr) 無法獲取分配大小
  4. 結構體尾部填充:struct { char c; } 大小為 1,但 struct { char c; double d; } 大小為 16 而非 9
  5. #pragma pack(n) 可改變對齊數,但可能導致非對齊訪問性能下降或硬件異常

最佳實踐建議

  • 用 sizeof(變量) 而非 sizeof(類型),避免類型變更時忘記更新
  • 結構體設計時,按類型大小遞減排序成員(或按對齊要求遞減)
  • 網絡傳輸/文件存儲結構體時,注意端序與填充字節,建議逐成員序列化
  • 嵌入式開發中,#pragma pack(1) 可壓縮結構體,但需確認 CPU 支持非對齊訪問
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved