| 左側 (目標類型) | 右側 (源類型) | 轉換動作 | 範例結果 |
| 整型 (int, long...) | 浮點型 (float, double) | 截斷小數部分 (向零取整,非四捨五入) | int a = 3.9; // a=3
int b = -3.9; // b=-3 |
| 浮點型 (float, double) | 整型 (int, long...) | 數值不變,轉為浮點表示 (補 .0) | float f = 5; // f=5.0 |
| 字符型 (char) | 整型 | 取低 8 位 (模 256),有符號 char 實現定義 | char c = 300; // 300%256=44 |
| 整型 | 字符型 | ASCII 碼值零擴展到整型寬度 | int i = 'A'; // i=65 |
| 長整型 | 短整型 | 符號擴展 (有符號) / 零擴展 (無符號) | long L = (short)-1; // L=-1 |
| 指針 | 整型/指針 | 整型轉指針需強制轉換,指針類型需兼容 | int *p = (int*)0x1000; |
經典範例:類型轉換演示
- int main(){
- int a, b = 322;
- float x, y = 8.88;
- char c1 = 'k', c2;
- a = y; // 實→整:a = 8 (截斷 .88)
- x = b; // 整→實:x = 322.0
- a = c1; // 字符→整:a = 'k' 的 ASCII 107
- c2 = b; // 整→字符:取低 8 位,322=0x142→0x42=66='B'
- printf("%d,%f,%d,%c", a, x, a, c2);
- }
輸出:107,322.000000,107,B
復合賦值運算符:11 種語法糖
形式:變量 雙目運算符= 表達式
等價於:變量 = 變量 運算符 表達式(但變量只求值一次)
完整家族對照表
| 運算符 | 名稱 | 等價展開 | 範例 | 適用類型 |
+= | 加法賦值 | a = a + b | a += 5 | 算術、指針 |
-= | 減法賦值 | a = a - b | x -= y + 7 | 算術、指針 |
*= | 乘法賦值 | a = a * b | x *= 2 | 算術 |
/= | 除法賦值 | a = a / b | x /= y | 算術 |
%= | 取模賦值 | a = a % b | r %= p | 整數 |
<<= | 左移賦值 | a = a << b | x <<= 2 | 整數 |
>>= | 右移賦值 | a = a >> b | x >>= 1 | 整數 |
&= | 位與賦值 | a = a & b | flags &= MASK | 整數 |
^= | 位異或賦值 | a = a ^ b | x ^= KEY | 整數 |
|= | 位或賦值 | a = a | b | flags |= BIT | 整數 |
核心優勢:單次求值
// 關鍵差異:左側變量只求值一次
arr[hash(key)] += 1; // hash(key) 只算一次
// vs
arr[hash(key)] = arr[hash(key)] + 1; // hash(key) 算兩次(除非編譯器優化)
對於有副作用的左側(如函數調用、指針解引用、volatile),差異更大:
*get_ptr() += 1; // get_ptr() 只調用一次
*get_ptr() = *get_ptr() + 1; // get_ptr() 調用兩次!
位運算賦值實戰模式
// 位掩碼操作:標準模式
flags |= BIT; // 置位
flags &= ~BIT; // 清位
flags ^= BIT; // 翻轉
flags &= MASK; // 保留特定位
flags |= (val << SHIFT) & MASK; // 寫入字段
⚠️ 經典陷阱與避坑指南
🚫 陷阱 1:浮點數賦值給整型的截斷陷阱
double price = 19.99;
int cents = price * 100; // 危險!19.99*100 可能是 1998.999... → 1998
// 安全
int cents = (int)round(price * 100);
🚫 陷阱 2:復合賦值與運算符優先級
x *= y + 1; // 等價 x = x * (y + 1) ✅
// 不是 x = x * y + 1
// 因為 = 及 復合賦值 優先級極低,右側完整表達式優先計算
🚫 陷阱 3:字符賦值溢出
char c = 200; // 有符號 char 通常 -128~127,溢出行為實現定義
unsigned char uc = 200; // 正確,0~255
🚫 陷阱 4:指針算術與復合賦值
int *p = arr;
p += 5; // p 指向 arr[5],正確 (指針算術單位為 sizeof(int))
p = p + 5; // 等價
賦值表達式在控制結構中的高級用法
1. 循環中讀取並判斷
int c;
while ((c = getchar()) != EOF) { ... }
2. 條件判斷中賦值
if ((fd = open("file", O_RDONLY)) < 0) { perror("open"); }
3. 避免重複計算
// 計算 sqrt 只一次
if ((disc = b*b - 4*a*c) >= 0) {
root = sqrt(disc);
}
總結
C 語言將賦值設計為運算符而非語句,構建了賦值表達式體系,核心特徵:
- 右結合性:支援鏈式賦值
a=b=c=0
- 有值有類型:可嵌套於任意表達式
x=(a=5)+(b=8)
- 隱式類型轉換:右側向左側類型轉換(截斷/擴展/位截取)
- 11 種復合賦值:語法糖+單次求值優勢,位運算領域不可或缺
深入理解這些機制,能避開浮點截斷、字符溢出、優先級誤解等經典坑,並靈活運用賦值表達式簡化控制流、減少重複計算、實現緊湊高效的系統級代碼。
- 上一篇文章: C語言逗號運算符與逗號表達式:被忽視的序列點藝術
- 下一篇文章: C語言算術運算符與算術表達式:優先級、結合性、自增自減完整指南
Copyright ©
程式碼之家 All Rights Reserved