| 維度 | 變量定義時初始化 | 賦值語句 |
| 語法位置 | 聲明語句中 | 可執行語句中 |
| 語法形式 | int a = 5, b, c = 10; | a = 5; b = c = 10; |
| 多變量連續 | 不允許 int a = b = c = 5; ❌ | 允許 a = b = c = 5; ✅ |
| 分隔符 | 變量間用逗號 , | 語句間用分號 ; |
| 執行時機 | 編譯/載入階段 (靜態) 或進入作用域時 (自動) | 程式運行到該行時 |
正確初始化寫法
// 錯誤 ❌
int a = b = c = 5;
// 正確 ✅
int a = 5, b = 5, c = 5;
// 或
int a = 5, b = 5, c = 5;
// 甚至
int a = 5, b = a, c = b; // 後者可用前者初始化
賦值表達式 vs 賦值語句:關鍵邊界
賦值表達式 是表達式的一種,有值、有類型、可嵌套,可出現在任何允許表達式的地方。
賦值語句 是賦值表達式加分號構成的語句,無值、不可嵌套在表達式中。
合法:賦值表達式用於條件判斷
- if ((x = y + 5) > 0) // 先賦值 x=y+5,再判斷 x>0
- z = x;
功能:計算 y+5 賦給 x,若結果 > 0 則執行 z=x。
非法:賦值語句用於表達式中
- if ((x = y + 5;) > 0) z = x; // ❌ 語法錯誤!分號不能在表達式中
嵌套賦值表達式的實戰模式
模式 1:循環中讀取並判斷
- int c;
- while ((c = getchar()) != EOF) {
- putchar(c);
- }
經典「讀取-檢查-處理」單行模式,利用賦值表達式的值參與比較。
模式 2:鏈式初始化多個變量
// 函數內部,非聲明處
x = y = z = 0; // 快速歸零
模式 3:複雜表達式中副作用賦值
// 計算 x+y 並存入 sum,同時參與外層運算
result = (sum = x + y) * 2 + sum; // sum 被賦值且使用兩次
類型轉換規則:賦值兩側類型不同時
系統自動將右側類型轉換為左側類型(隱式類型轉換)。
| 左側 (目標) | 右側 (源) | 轉換規則 | 範例 |
| 整型 (int) | 浮點型 (float/double) | 截斷小數部分(非四捨五入) | int a = 3.14; // a=3 |
| 浮點型 (float/double) | 整型 (int/long) | 數值不變,轉為浮點表示(補 .0) | float f = 5; // f=5.0 |
| 字符型 (char) | 整型 (int) | 取低 8 位 (模 256) | char c = 300; // c=44 (300%256) |
| 整型 (int) | 字符型 (char) | ASCII 碼值擴展(高位補 0) | int i = 'A'; // i=65 |
| 長整型 | 短整型 | 符號擴展 / 零擴展 | long L = (short)-1; // L=-1 |
經典範例:類型轉換演示
- 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
復合賦值運算符:語法糖與效能
完整列表
| 運算符 | 等價展開 | 範例 |
+= | a = a + b | a += 5 → a = a + 5 |
-= | a = a - b | x -= y + 7 → x = x - (y + 7) |
*= | a = a * b | |
/= | a = a / b | |
%= | a = a % b | r %= p → r = r % p |
<<= | a = a << b | 左移賦值 |
>>= | a = a >> b | 右移賦值 |
&= | a = a & b | 位與賦值 |
^= | a = a ^ b | 位異或賦值 |
|= | a = a | b | 位或賦值 |
優勢
- 可讀性:
total += item 比 total = total + item 更清晰表達「累加」意圖
- 效能:早期編譯器優化生成更好機器碼(現代編譯器對簡單情況優化相同)
- 避免重複求值:
arr[hash(key)] += 1 中 hash(key) 只算一次
⚠️ 經典陷阱與避坑指南
🚫 陷阱 1:= 與 == 混淆
if (x = 5) // 永遠為真!賦值 5 給 x,表達式值 5 (真)
// 正確
if (x == 5) // 比較
// 防禦性寫法:常量放左邊
if (5 == x) // 若誤寫 5 = x 編譯報錯
🚫 陷阱 2:浮點數賦值給整型的精度丟失
double price = 19.99;
int cents = price * 100; // 危險!可能得到 1998 (浮點誤差)
// 安全
int cents = (int)round(price * 100);
🚫 陷阱 3:字符賦值溢出
char c = 200; // 有符號 char 範圍 -128~127,溢出實現定義
unsigned char uc = 200; // 正確,範圍 0~255
🚫 陷阱 4:條件運算符優先級導致的賦值錯誤
int a = 0, b = 0;
a = b = 5 > 3 ? 10 : 20; // 等價 a = (b = (5>3?10:20)) → a=b=10 ✅
// 但
a = b = 5 > 3 ? 10 : 20; // 同樣,條件運算符優先級高於 =
最佳實踐清單
- 初始化即定義:
int x = get_value(); 而非先聲明後賦值
- 鏈式賦值僅用於同類型同值初始化:
a = b = c = 0;
- 複雜條件中賦值加括號:
if ((fd = open(...)) < 0)
- 避免隱式縮窄轉換:開啟編譯警告
-Wconversion -Wnarrowing
- 復合賦值表達意圖:累加用
+=,位掩碼用 &=/|=
- 常量左側防誤賦:
if (MAX_SIZE == n)
總結
賦值語句雖是 C 語言最基礎構建塊,但其右結合性、表達式/語句二元性、隱式類型轉換、初始化與賦值的語法邊界構成了豐富的語義空間。深入理解這些機制,不僅能避開 =/== 混淆、浮點截斷、字符溢出等經典坑,更能靈活運用鏈式賦值、條件中賦值、復合賦值等高級模式,寫出簡潔、高效、意圖清晰的 C 代碼。
- 上一篇文章: C語言數據輸入輸出基礎:stdio.h庫函數體系概覽
- 下一篇文章: C語言語句分類總覽:五大類語句構建程式骨架
Copyright ©
程式碼之家 All Rights Reserved