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

C 語言位運算不改變操作數值:原理、陷阱與正確用法

     編輯:C 語言問答

核心結論

位運算符 (&, |, ^, ~, <<, >>) 僅對操作數的「值」進行運算,產生新的「結果值」,絕不修改操作數本身的儲存內容。

代碼驗證


#include <stdio.h>

int main() {
    unsigned char a = 0x0F; // 0000 1111
    unsigned char b = 0xF0; // 1111 0000

    printf("a = 0x%02X, b = 0x%02X\n", a, b);

    // 1. 位與 &
    unsigned char c = a & b; // 0x00
    printf("a & b = 0x%02X, a = 0x%02X (未變)\n", c, a);

    // 2. 位或 |
    c = a | b; // 0xFF
    printf("a | b = 0x%02X, a = 0x%02X (未變)\n", c, a);

    // 3. 位異或 ^
    c = a ^ b; // 0xFF
    printf("a ^ b = 0x%02X, b = 0x%02X (未變)\n", c, b);

    // 4. 位取反 ~ (單目)
    c = ~a;    // 0xF0
    printf("~a = 0x%02X, a = 0x%02X (未變)\n", c, a);

    // 5. 左移 <<
    c = a << 2; // 0x3C (0011 1100)
    printf("a << 2 = 0x%02X, a = 0x%02X (未變!)\n", c, a);

    // 6. 右移 >>
    c = b >> 2; // 0x3C
    printf("b >> 2 = 0x%02X, b = 0x%02X (未變!)\n", c, b);

    // 對比:賦值複合運算符 **會** 修改
    a <<= 2; // 等價 a = a << 2
    printf("a <<= 2 後, a = 0x%02X (已修改!)\n", a);

    return 0;
}

為什麼初學者會誤以為會改變?

  1. 混淆 op 與 op=:a << 2 不變,a <<= 2 變。
  2. 其他語言行為不同:某些語言 (如 Python 整數不可變,但列表 list += 就地修改) 或汇编指令直接操作暫存器。
  3. 副作用函數誤導:printf("%d", a++) 有副作用,誤以為運算子都有副作用。

嵌入式暫存器操作實戰模式


// 1. 讀取暫存器
uint32_t reg = REG_ADDR;

// 2. 位運算計算新值 (原值不變)
uint32_t new_val = (reg & ~MASK) | (value << SHIFT);

// 3. 寫回暫存器 (這裡才真正改變硬體狀態)
REG_ADDR = new_val;

// 常見宏封裝
#define SET_BIT(reg, bit)   ((reg) |= (1U << (bit)))
#define CLEAR_BIT(reg, bit) ((reg) &= ~(1U << (bit)))
#define TOGGLE_BIT(reg, bit) ((reg) ^= (1U << (bit)))
#define GET_BIT(reg, bit)   (((reg) >> (bit)) & 1U)

// 使用 (注意:宏參數若為暫存器地址,會直接修改硬體)
SET_BIT(GPIOA->ODR, 5); // 置位 PA5 輸出高電平

總結口訣

  • 單純運算符 (&, |, ^, ~, <<, >>):**只算不改**,結果需接收變數或直接用於表達式。
  • 複合賦值運算符 (&=, |=, ^=, <<=, >>=):**算完存回左操作數**,修改左值。
  • 暫存器操作三步走:讀 → 算 (不改原變數) → 寫。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved