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

C語言賦值運算符與賦值表達式:從基礎到復合賦值的完整指南

     編輯:關於C語言

賦值運算符是 C 語言中最基礎、使用頻率最高、且獨具特色的運算符。不同於其他語言將賦值視為語句,C 語言將 = 設計為運算符,從而構成賦值表達式——具有值、類型、可嵌套、可參與更大表達式運算。這一設計賦予了 C 語言極大的表達靈活性,但也帶來了類型轉換、優先級、副作用等深層機制。本文系統講解簡單賦值、類型轉換規則、復合賦值運算符全家族。

簡單賦值運算符 =

語法與語義

變量 = 表達式
  • 功能:計算右側表達式值,存入左側變量內存單元
  • 結果:賦值表達式的值 = 右側表達式的值(經類型轉換後)
  • 類型:左側變量的類型
  • 結合性:右結合性 (Right-to-Left)
  • 左值要求:左側必須是可修改的左值(變量、解引用指針、數組元素等)

右結合性實例

a = b = c = 5;

等價於:a = (b = (c = 5))

執行順序:c=5 → 值 5 → b=5 → 值 5 → a=5 → 整式值 5

賦值表達式可嵌套的威力

x = (a = 5) + (b = 8);  // 合法!
// 1. a=5,表達式值 5
// 2. b=8,表達式值 8
// 3. 5+8=13 賦給 x
// 結果: a=5, b=8, x=13

這在其他語言中通常需要多條語句,C 語言一行搞定。

賦值中的類型轉換規則

當 = 兩側類型不同時,右側值隱式轉換為左側類型。

轉換規則表

經典範例:類型轉換演示

  1. int main(){
  2. int a, b = 322;
  3. float x, y = 8.88;
  4. char c1 = 'k', c2;
  5. a = y; // 實→整:a = 8 (截斷 .88)
  6. x = b; // 整→實:x = 322.0
  7. a = c1; // 字符→整:a = 'k' 的 ASCII 107
  8. c2 = b; // 整→字符:取低 8 位,322=0x142→0x42=66='B'
  9. printf("%d,%f,%d,%c", a, x, a, c2);
  10. }

輸出:107,322.000000,107,B

復合賦值運算符:11 種語法糖

形式:變量 雙目運算符= 表達式

等價於:變量 = 變量 運算符 表達式(但變量只求值一次)

完整家族對照表

左側 (目標類型)右側 (源類型)轉換動作範例結果
整型 (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;

核心優勢:單次求值

// 關鍵差異:左側變量只求值一次
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 語言將賦值設計為運算符而非語句,構建了賦值表達式體系,核心特徵:

  1. 右結合性:支援鏈式賦值 a=b=c=0
  2. 有值有類型:可嵌套於任意表達式 x=(a=5)+(b=8)
  3. 隱式類型轉換:右側向左側類型轉換(截斷/擴展/位截取)
  4. 11 種復合賦值:語法糖+單次求值優勢,位運算領域不可或缺

深入理解這些機制,能避開浮點截斷、字符溢出、優先級誤解等經典坑,並靈活運用賦值表達式簡化控制流、減少重複計算、實現緊湊高效的系統級代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
運算符名稱等價展開範例適用類型
+=加法賦值a = a + ba += 5算術、指針
-=減法賦值a = a - bx -= y + 7算術、指針
*=乘法賦值a = a * bx *= 2算術
/=除法賦值a = a / bx /= y算術
%=取模賦值a = a % br %= p整數
<<=左移賦值a = a << bx <<= 2整數
>>=右移賦值a = a >> bx >>= 1整數
&=位與賦值a = a & bflags &= MASK整數
^=位異或賦值a = a ^ bx ^= KEY整數
|=位或賦值a = a | bflags |= BIT整數