C 語言類型系統是理解內存佈局、運算語義、移植性邊界的核心。本文系統梳理整數家族、浮點標準、邏輯類型演進、隱式/顯式轉換規則、條件運算符與逗號運算符細節,並結合內存模型、硬件實現、標準演進(C89/C99/C11)提供工程級認知框架。
| 類別 | 關鍵字 | 典型尺寸 | 表示範圍/精度 | 核心屬性 |
|---|---|---|---|---|
| 整數 | char | 1 Byte | -128~127 / 0~255 | 最小寻址單元,字符/小整數 |
short | 2 Bytes | -32768~32767 | 至少16位 | |
int | 4 Bytes | -2^31~2^31-1 | 「機器字長」,CPU最愛,通常最快 | |
long | 4/8 Bytes | LP64模型8字節 | 至少32位,64位系統常為64位 | |
long long | 8 Bytes | -2^63~2^63-1 | C99引入,保證64位 | |
| 浮點 | float | 4 Bytes | ~7位有效數字,範圍±10^38 | IEEE 754 單精度 |
double | 8 Bytes | ~15位有效數字,範圍±10^308 | IEEE 754 雙精度,現代CPU首選 | |
long double | 10/16 Bytes | ≥double精度 | 擴展精度,x86常為80位 | |
| 邏輯 | _Bool / bool | 1 Byte | 0/1 | C99 <stdbool.h> 提供 true/false |
| 指針 | void * 等 | 4/8 Bytes | 地址空間 | 架構相關,32/64位 |
// 8位補碼示例 00000000 = 0 00000001 = 1 ... 01111111 = 127 10000000 = -128 (最小值) 11111111 = -1 (全1 = -1) 11111110 = -2 // 關鍵公式:-x = ~x + 1 (按位取反加一) // 無符號視為純二進制:11111111 = 255
UINT_MAX + 1 = 0)。if (x+1 > x) ... 恆真被優化)。123 // int
123U // unsigned int
123L // long
123LL // long long
123ULL // unsigned long long
printf("%d %u %ld %lld", i, u, l, ll); // 格式必須匹配類型,否則 UB
| 符號位(1) | 指數位(8) | 尾數位(23) | // 實際值 = (-1)^S × 1.M × 2^(E-127) (規格化數) // 特殊值:E=0,M=0 → ±0;E=255,M=0 → ±inf;E=255,M≠0 → NaN
float a = 1.34f, b = 1.22f, c = a + b; // c = 2.5599999...
if (c == 2.56f) printf("equal"); // 失敗!
// 正確比較:相對/絕對誤差
#define EPS 1e-6
if (fabs(c - 2.56f) < EPS) printf("approx equal");
double:現代 64 位 CPU 硬件直接支持,速度不慢,精度高,printf 參數默認提升為 double。float。long double 僅用於特殊高精度需求(如金融中間計算),注意 printf 用 %Lf。<stdbool.h>// C89:無 bool,用 int,0 假,非0 真 // C99:#include提供 #define bool _Bool #define true 1 #define false 0 // 邏輯運算符:短路求值 // ! (非) > && (與) > || (或) 優先級遞減 // 短路特性:&& 左側假則右側不算;|| 左側真則右側不算 // 區間判斷錯誤寫法:4 < x < 6 → (4 4 && x < 6)
char c = 100; short s = 200; int result = c + s; // c,s 先提升為 int 再相加
// 規則:低精度向高精度轉換,無符號優於有符號(同寬度時)
int i = -1;
unsigned u = 1;
if (i < u) printf("true"); // false! i 轉為 unsigned 變巨大值 4294967295
double a = 1.0, b = 2.0; int i = (int)a / b; // (int)1.0 = 1 → 1/2 = 0 (整數除法) int j = (int)(a / b); // a/b = 0.5 → (int)0.5 = 0 int c = 5, d = 6; double e = (double)(c / d); // c/d = 0 (整除) → 0.0 double f = (double)c / d; // 5.0/6 = 0.833...
printf("%d\n", (short)32768); // -32768 (溢出截斷)
printf("%d\n", (char)32768); // 0 (低8位全0)
int k = 32768;
short kk = (short)k; // kk = -32768,但 k 仍為 32768
?:`int max = (a > b) ? a : b; // 單表達式,非語句 // 優先級:高於賦值,低於邏輯/算術 // 結合性:右結合 a?b:c?d:e 等價 a?b:(c?d:e) // 類型兼容:第二/三操作數經常見算術轉換得出結果類型 double d = (flag) ? 1 : 2.0; // 結果類型 double
,`// 最低優先級,左結合,值為右側表達式值 int n = (1+2, 3+4); // n = 7,左側 1+2 被丟棄(但副作用保留) int m = 1+2, 3+4; // m = 3,逗號這裡是聲明分隔符,非運算符! // 典型用途:for 循環多變量更新 for (int i=0, j=10; i七、 總結:類型選擇決策樹
- 整數計算 →
int(最快,自然字長);需明確寬度用int32_t/int64_t(<stdint.h>)。- 位操作/硬件寄存器 →
uint32_t等無符號定寬類型。- 浮點計算 →
double(默認);極端精度long double;存儲優化float。- 邏輯判斷 →
bool(<stdbool.h>)。- 格式化輸入輸出 → 嚴格匹配
%d/%u/%ld/%lld/%f/%lf/%Lf,錯配導致 UB。核心認知:類型不僅是編譯器的標籤,更是內存位模式的解釋協議。理解補碼、IEEE 754、整數提升、常見算術轉換,才能寫出可移植、無 UB、高性能的 C 代碼。現代 C 開發請善用
<stdint.h>、<stdbool.h>、static_assert、編譯器警告 (-Wall -Wextra -Wconversion -Wsign-conversion) 讓類型系統為你把關。