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

C Primer Plus 學習筆記(第 15 章):位操作完全指南 —— 位邏輯、移位、掩碼、位字段

     編輯:關於C語言

15.1 二進制基礎

  • 位:最小信息單位,0/1。
  • 字節:8 位 (現代系統標準)。
  • 有符號整數表示:二進制補碼 (Two's Complement) 統治一切。
    • 正數:最高位 0,值同原碼。
    • 負數:對應正數按位取反 + 1。
      例:-5 (8位) → 00000101 → 取反 11111010 → +1 11111011 (即 0xFB)。
    • 優勢:唯一零表示、加減法統一、硬件簡單。
  • 浮點數:IEEE 754 標準 (符號位 + 指數位 + 尾數位),非重點。

15.2 位邏輯運算符

運算符名稱真值表典型用途
~按位取反 (一元)0→1, 1→0生成掩碼、翻轉標志位
&按位與1&1=1, 其他=0清零位、檢查位、掩碼提取
|按位或0|0=0, 其他=1置位、合併標志位
^按位異或相同=0, 不同=1翻轉位、簡單加密、交換變量

15.3 掩碼技術

掩碼:特定位為 1、其餘為 0 的常量,用於操作目標值的特定位。


#define MASK_BIT(n) (1u << (n)) // 第 n 位為 1 (從 0 開始)

unsigned int flags = 0;

// 置位 (開啟第 3 位)
flags |= MASK_BIT(3);

// 清零 (關閉第 3 位)
flags &= ~MASK_BIT(3);

// 翻轉 (切換第 3 位)
flags ^= MASK_BIT(3);

// 檢查 (第 3 位是否為 1)
if (flags & MASK_BIT(3)) { ... }

// 批量操作
#define READY_MASK  0x01 // bit 0
#define ERROR_MASK  0x02 // bit 1
#define BUSY_MASK   0x04 // bit 2
flags |= READY_MASK | BUSY_MASK; // 同時置位
flags &= ~(ERROR_MASK | BUSY_MASK); // 同時清零

15.4 移位運算符

運算符行為等價算術注意事項
<<左移,低位補 0,高位丟棄乘 2n (無溢出時)有符號左移溢出為 UB
>>右移,高位:無符號補 0,有符號實現定義 (通常算術移位補符號位)除 2n (非負時)負數右移結果依賴編譯器

實用技巧:顏色分量提取


#define BYTE_MASK 0xFF

unsigned long color = 0x002A162F; // RRGGBB
unsigned char red   =  color        & BYTE_MASK;       // 2F
unsigned char green = (color >> 8)  & BYTE_MASK;       // 16
unsigned char blue  = (color >> 16) & BYTE_MASK;       // 2A

實用技巧:反轉整數最後 n 位


int invert_end(int num, int bits) {
    unsigned int mask = 0;
    for (int i = 0; i < bits; i++) mask |= (1u << i); // 低 bits 位全 1
    return num ^ mask;
}

15.5 位字段

在結構體中指定成員佔用的位數,編譯器自動打包。


struct PrinterFlags {
    unsigned int auto_feed : 1;
    unsigned int bold      : 1;
    unsigned int underline : 1;
    unsigned int italic    : 1;
    unsigned int reserved  : 28; // 填充到 32 位
} prnt;

prnt.bold = 1;       // 直接賦值 0/1
prnt.italic = 0;
// 編譯器自動生成掩碼、移位代碼

位字段細節

  • 類型必須是 int、signed int、unsigned int (C99 允許 _Bool)。
  • 寬度不可超過類型位寬。
  • 內存佈局實現定義 (位順序、跨邊界處理),不可用於網絡協議/文件格式 (需手動打包)。
  • sizeof(struct) 通常為 4/8 字節 (對齊單位)。
  • 無法取址 &prnt.bold (非字節對齊)。

15.6 綜合案例:簡易權限系統


enum Perm { READ = 1<<0, WRITE = 1<<1, EXEC = 1<<2, ADMIN = 1<<3 };

void grant(int *perm, int p) { *perm |= p; }
void revoke(int *perm, int p) { *perm &= ~p; }
bool check(int perm, int p) { return (perm & p) == p; }

int main() {
    int user = 0;
    grant(&user, READ | WRITE);
    printf("Has READ? %d\n", check(user, READ)); // 1
    revoke(&user, WRITE);
    printf("Has WRITE? %d\n", check(user, WRITE)); // 0
    return 0;
}

避坑指南

  1. 有符號移位 UB:左移導致符號位改變、右移負數 → 改用無符號類型。
  2. 移位寬度 ≥ 類型寬度:1 << 32 (32位 int) 為 UB → 用 1ull << 32。
  3. 位字段不可移植:跨平台/網絡傳輸手動 htonl/掩碼打包。
  4. 優先用標準庫:<stdint.h> 固定寬度、<stdatomic.h> 原子位操作 (C11)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved