位運算符 (&, |, ^, ~, <<, >>) 僅對操作數的「值」進行運算,產生新的「結果值」,絕不修改操作數本身的儲存內容。
#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;
}
op 與 op=:a << 2 不變,a <<= 2 變。list += 就地修改) 或汇编指令直接操作暫存器。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 輸出高電平
&, |, ^, ~, <<, >>):**只算不改**,結果需接收變數或直接用於表達式。&=, |=, ^=, <<=, >>=):**算完存回左操作數**,修改左值。