數據類型是C語言類型系統的核心,決定變量佔用內存大小、取值範圍與操作語義。本文系統梳理基本類型、構造類型、類型修飾符及用戶自定義類型,附帶常見誤區與最佳實踐。
類型體系概覽
C語言類型
├── 基本類型(不可分解)
│ ├── 整型家族
│ ├── 浮點型家族
│ ├── 字符型
│ └── 無值型(void)
└── 構造類型(可分解為成員/元素)
├── 數組類型
├── 結構類型
├── 聯合類型
└── 指針類型(常歸屬構造類型)
基本類型詳解
1. 整型家族
| 類型 | 關鍵字 | 典型大小 | 典型範圍(32位系統) | 格式符 |
| 短整型 | short / short int | 2字節 | -32,768 ~ 32,767 | %hd |
| 整型 | int | 4字節 | -2,147,483,648 ~ 2,147,483,647 | %d |
| 長整型 | long / long int | 4/8字節 | 與int同或更大 | %ld |
| 長長整型 | long long (C99) | 8字節 | -9×10¹⁸ ~ 9×10¹⁸ | %lld |
修飾符組合:
signed(默認):有符號,最高位為符號位
unsigned:無符號,範圍翻倍(0 ~ 2ⁿ⁻¹),無符號運算規則
- 組合示例:
unsigned short、signed long long、unsigned int(可省略int)
字面量後綴:123(int)、123U(unsigned)、123L(long)、123LL(long long)、0x7F(十六進制)、0177(八進制)。
2. 浮點型家族
| 類型 | 關鍵字 | 典型大小 | 精度(有效數字) | 範圍約略 | 格式符 |
| 單精度 | float | 4字節 | 6~7位 | ±3.4×10⁻³⁸ ~ ±3.4×10³⁸ | %f / %e |
| 雙精度 | double | 8字節 | 15~16位 | ±1.7×10⁻³⁰⁸ ~ ±1.7×10³⁰⁸ | %lf / %e |
| 長雙精度 | long double | 10/12/16字節 | 19+位 | 更大 | %Lf |
關鍵點:浮點數以IEEE 754格式存儲(符號位+指數位+尾數位),不能精確表示所有十進制小數(如0.1)。比較用fabs(a-b) < EPS。
3. 字符型
char:1字節,存儲ASCII碼值(-128~127 或 0~255,視實現定義是否有符號)
- 字符字面量:
'A'、'\n'、'\x41'、'\101'
- 陷阱:
char是否有符號由編譯器決定,跨平台位操作必須顯式用signed char/unsigned char
4. 無值型 void
- 函數無返回值:
void func()
- 無參數函數:
void func(void)(C++中void func()等價)
- 通用指針:
void*可指向任意類型對象,不可直接解引用/算術運算
(void)expr:顯式丟棄表達式值,消除未使用警告
構造類型
數組類型
int arr[10]; // 定長數組
int arr[] = {1,2,3}; // 自動推導長度
int arr[3][4]; // 多維數組(行優先存儲)
- 數組名在大多數表達式中退化為指向首元素的指針(&arr[0])
- 例外:
sizeof(arr)、&arr、字符串字面量初始化
- 數組不可賦值(
arr1 = arr2非法),需memcpy或逐元素拷貝
結構類型 struct
struct Student {
char name[20];
int age;
float score;
};
struct Student s1 = {"Alice", 20, 92.5};
s1.age = 21; // 成員訪問
struct Student *p = &s1;
p->score = 95.0; // 指針訪問
- 內存佈局:成員按聲明順序連續存儲,可能有填充字節對齊
sizeof(struct) ≥ 成員大小之和
- 位域:
unsigned int flag:1;節省空間,跨平台佈局實現定義
聯合類型 union
union Data {
int i;
float f;
char c[4];
};
union Data d;
d.i = 0x41424344; // 佔用同一內存區域
// d.c[0]=='D', d.c[1]=='C'... (小端序)
- 所有成員共用同一塊內存,大小等於最大成員大小(對齊後)
- 同一時刻只能存儲一個成員值,讀取非活躍成員屬於實現定義行為
- 常用於:類型雙關、協議解析、節省內存的互斥字段
用戶自定義類型 typedef
typedef unsigned int uint32_t;
typedef struct { int x, y; } Point;
typedef void (*Callback)(int);
uint32_t id = 100;
Point p = {10, 20};
Callback cb = my_func;
- 不創建新類型,只是別名,與原類型完全等價
- 簡化複雜聲明、增強可讀性、平台相關類型抽象
- 慣例:
_t後綴表示類型別名(POSIX標準)
類型大小與對齊(關鍵實現細節)
| 類型 | 對齊要求 | 備註 |
| char | 1 | 無對齊要求 |
| short | 2 | 地址為2的倍數 |
| int/float | 4 | 地址為4的倍數 |
| double/long/pointer | 4/8 | 32位系統通常4,64位系統8 |
| struct | 最大成員對齊 | 整體大小為對齊的倍數 |
編譯器在結構體成員間插入填充字節滿足對齊,可用#pragma pack(n)或屬性__attribute__((packed))控制(影響性能/移植性)。
常見誤區與最佳實踐
| 誤區 | 正確認知 |
| int總是4字節 | C標準只保證short ≤ int ≤ long,最小16位。嵌入式常見16位int |
| char是有符號的 | 實現定義,ARM常為unsigned,x86常為signed |
| float精度夠用 | 金融/科學計算必須用double或定點數 |
| 結構體大小=成員和 | 忽略了對齊填充 |
| union可同時訪問多成員 | 同一時刻只有一個活躍成員 |
現代C建議(C99/C11)
- 使用
<stdint.h>固定寬度類型:int32_t, uint64_t, intptr_t
- 使用
<stdbool.h>的bool, true, false
- 避免直接用基本類型,定義語義化類型別名:
typedef int32_t UserId;
- 結構體成員按大小降序排列可減少填充
- 跨模塊接口使用固定寬度類型保證ABI穩定
深入理解C類型系統的語義、存儲佈局與轉換規則,是編寫高效、可移植、無未定義行為代碼的基石。
- 上一篇文章: C語言運算符與表達式全面解析:優先級、類型轉換與條件運算
- 下一篇文章: C語言常量與變量基礎:定義、初始化、類型與轉義字符詳解
Copyright ©
程式碼之家 All Rights Reserved