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

C++ 位運算技巧:特殊表達式 x&(x-1)、平均值無溢出、指針重解釋深度解析

     編輯:C++ 入門

表達式一:x & (x - 1) —— 統計二進制中 1 的個數


int countOnes(int x) {
    int cnt = 0;
    while (x) {
        ++cnt;
        x &= (x - 1); // 清除最低位的 1
    }
    return cnt;
}
// 示例:x = 9999 (二進制 10011100001111) → 8 個 1

原理:x-1 將最低位 1 變為 0,該位右側所有 0 變為 1。x & (x-1) 保留高位不變,最低位 1 清零,右側全 0。每次循環消除一個 1,循環次數即為 1 的個數 (Hamming Weight)。

應用:判斷 2 的冪次 (x & (x-1) == 0)、子集枚舉、位圖操作。

表達式二:(x & y) + ((x ^ y) >> 1) —— 無溢出平均值


unsigned char avg(unsigned char x, unsigned char y) {
    return (x & y) + ((x ^ y) >> 1);
}
// 測試
avg(2, 8)   // 5
avg(5, 5)   // 5
avg(5, 6)   // 5
avg(255, 255) // 255 (不溢出!)

推導:逐位分解平均值 (x+y)/2:

  • 同為 1 的位:1+1=2,平均 1 → x & y 保留這些位。
  • 一 0 一 1 的位:1+0=1,平均 0.5 → 向下取整 0,但進位影響鄰位。(x ^ y) >> 1 將異或結果右移,正好是這些位貢獻的進位部分。
  • 同為 0 的位:貢獻 0。

優勢:無中間和溢出風險,適用於定寬整數類型 (如 uint8_t、uint16_t) 的匯編/嵌入式場景。

表達式三:(int&a) vs (int)a —— 指針重解釋 vs 類型轉換


float a = 1.0f;
std::cout << (int)a;     // 1 (值轉換:浮點數 1.0 → 整數 1)
std::cout << (int&a);    // 1065353216 (位模式重解釋:IEEE 754 0x3F800000 → 整數)

float b = 0.0f;
std::cout << (int)b;     // 0
std::cout << (int&b);    // 0 (0.0f 位模式全 0)

本質區別:

  • (int)a:值轉換,按語義將浮點數值轉為整數值,生成新對象。
  • (int&a):類型重解釋 (Reinterpret Cast),告訴編譯器「將這塊內存當作 int 看待」,不改變比特位,屬於 reinterpret_cast<int&>(a)。

嚴重警告:

  1. 違反嚴格別名規則,導致未定義行為 (UB),編譯器優化可能產生錯誤代碼。
  2. 正確做法:std::memcpy、std::bit_cast (C++20)、union (C++ 標準允許聯合體類型雙向轉換)。

// 安全做法 C++20
#include <bit>
int bits = std::bit_cast<int>(1.0f); // 1065353216

// C++17 兼容
int bits;
static_assert(sizeof(float) == sizeof(int));
std::memcpy(&bits, &a, sizeof(a));

總結表

表達式功能核心原理現代 C++ 替代
x & (x-1)清除最低位 1 / 計數 1 的個數二進制減法借位特性std::popcount (C++20)
(x&y)+((x^y)>>1)無溢出平均值逐位分解加法進位(x+y)>>1 (無符號安全) / std::midpoint (C++20)
(int&a)位模式重解釋違反嚴格別名規則 (UB)std::bit_cast / memcpy

最佳實踐

  1. 優先使用標準庫算法 (popcount, midpoint, bit_cast),可讀、安全、編譯器優化最好。
  2. 嵌入式/舊標準環境下使用位運算技巧,添加詳細註釋說明原理。
  3. 絕不使用 C 風格強轉 (Type&) 進行類型重解釋,改用 reinterpret_cast 明確意圖 (仍需承擔 UB 風險)。
  4. 理解 IEEE 754 浮點數位模式:符號位(1) + 指數位(8) + 尾數位(23),1.0f = 0x3F800000。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved