C++位操作實(shí)戰(zhàn)掩碼、提取與組裝
在C++編程中,位操作是一項(xiàng)基礎(chǔ)且強(qiáng)大的技術(shù),它允許程序員在二進(jìn)制級(jí)別上直接操作數(shù)據(jù)。這種能力對(duì)于性能優(yōu)化、內(nèi)存節(jié)省以及底層硬件控制至關(guān)重要。本文將深入探討C++中的掩碼操作、字節(jié)提取與組裝,并通過(guò)實(shí)例展示這些技術(shù)的實(shí)際應(yīng)用。
一、位運(yùn)算符基礎(chǔ)
C++中的基本位運(yùn)算符:
- 按位與(&):對(duì)兩個(gè)數(shù)的每一位執(zhí)行與操作,僅當(dāng)兩個(gè)相應(yīng)的位都為1時(shí),結(jié)果的該位才為1。
- 按位或(|):對(duì)兩個(gè)數(shù)的每一位執(zhí)行或操作,只要有一個(gè)相應(yīng)的位為1,結(jié)果的該位就為1。
- 按位異或(^):對(duì)兩個(gè)數(shù)的每一位執(zhí)行異或操作,當(dāng)兩個(gè)相應(yīng)的位不同時(shí),結(jié)果的該位為1,相同時(shí)為0。
- 按位取反(~):對(duì)一個(gè)數(shù)的每一位執(zhí)行取反操作,0變?yōu)?,1變?yōu)?。
- 左移(<<):將一個(gè)數(shù)的所有位向左移動(dòng)指定的位數(shù),右邊補(bǔ)0。左移相當(dāng)于對(duì)數(shù)字進(jìn)行2的n次冪的乘法運(yùn)算(n為移動(dòng)的位數(shù))。
- 右移(>>):將一個(gè)數(shù)的所有位向右移動(dòng)指定的位數(shù)。對(duì)于無(wú)符號(hào)數(shù),高位補(bǔ)0;對(duì)于有符號(hào)數(shù),處理方式因編譯器而異,可能補(bǔ)符號(hào)位(算術(shù)右移)或補(bǔ)0(邏輯右移)。
示例1:按位與(清零、取指定位)
#include <stdio.h> int main() { int targetValue = 0b11011010; // 二進(jìn)制表示法 int mask = 0b00110011; int result = targetValue & mask; // 應(yīng)用掩碼,保留掩碼中為1的位 printf("原始: %08b\n", targetValue); printf("掩碼: %08b\n", mask); printf("結(jié)果: %08b\n", result); return 0; }
輸出:
原始: 11011010
掩碼: 00110011
結(jié)果: 00011010
示例2:按位或(保留指定位)
#include <stdio.h> int main() { int a = 0b00101011; int b = 0b10010100; int result = a | b; // 按位或運(yùn)算 printf("a: %08b\n", a); printf("b: %08b\n", b); printf("結(jié)果: %08b\n", result); return 0; }
輸出:
a: 00101011
b: 10010100
結(jié)果: 10111111
示例3:按位異或(特定位翻轉(zhuǎn))
#include <stdio.h> int main() { int a = 0b01111010; int mask = 0b00001111; int result = a ^ mask; // 按位異或運(yùn)算,翻轉(zhuǎn)低4位 printf("原始: %08b\n", a); printf("掩碼: %08b\n", mask); printf("結(jié)果: %08b\n", result); return 0; }
輸出:
原始: 01111010
掩碼: 00001111
結(jié)果: 01110101
示例4:取反
#include <stdio.h> int main() { int a = 0b01111010; int result = ~a; // 取反運(yùn)算 printf("原始: %08b\n", a); printf("結(jié)果: %08b\n", result); return 0; }
輸出:
原始: 01111010
結(jié)果: 10000101
示例5:左移和右移
#include <stdio.h> int main() { int a = 0b00001111; // 15的二進(jìn)制表示 int leftShiftResult = a << 2; // 左移2位 int rightShiftResult = a >> 2; // 右移2位(邏輯移位) printf("原始: %08b\n", a); printf("左移2位: %08b\n", leftShiftResult); // 相當(dāng)于乘以4,結(jié)果為60 printf("右移2位: %08b\n", rightShiftResult); // 相當(dāng)于除以4,結(jié)果為3或-4(取決于符號(hào)位和移位方式) return 0; }
輸出(假設(shè)為邏輯移位):
原始: 00001111
左移2位: 00111100
右移2位: 00000011
二、掩碼操作實(shí)戰(zhàn)
掩碼是一個(gè)二進(jìn)制數(shù),用于屏蔽不需要的位,只保留目標(biāo)位。通過(guò)與操作(&),可以保留掩碼中為1的位,其他位都被清零。在C/C++中使用掩碼操作來(lái)設(shè)置、清除和檢查整數(shù)的特定位。這些技術(shù)在性能優(yōu)化、內(nèi)存節(jié)省以及底層硬件控制中非常有用。
- 設(shè)置特定位:通過(guò)掩碼與或操作,可以設(shè)置整數(shù)的特定位。例如,要設(shè)置32位整數(shù)的第5位(從0開始計(jì)數(shù)),可以使用
num | (1 << 5)
。 - 清除特定位:通過(guò)掩碼與取反操作,可以清除整數(shù)的特定位。例如,要清除32位整數(shù)的第5位,可以使用
num & ~(1 << 5)
。 - 檢查特定位:通過(guò)與操作,可以檢查整數(shù)的特定位是否被設(shè)置。例如,要檢查32位整數(shù)的第5位是否被設(shè)置,可以使用
(num & (1 << 5)) != 0
。
示例1:設(shè)置特定位
假設(shè)我們有一個(gè)32位整數(shù)num,我們想要設(shè)置其中的第5位(從0開始計(jì)數(shù))。我們可以使用以下代碼:
#include <stdio.h> int main() { unsigned int num = 0; // 初始化為0 unsigned int mask = 1 << 5; // 創(chuàng)建一個(gè)掩碼,第5位為1,其他位為0 num |= mask; // 使用或操作設(shè)置第5位 printf("num: %u\n", num); // 輸出結(jié)果,應(yīng)該看到第5位被設(shè)置為1 return 0; }
示例2:清除特定位
現(xiàn)在,假設(shè)我們想要清除num的第5位。我們可以使用以下代碼:
#include <stdio.h> int main() { unsigned int num = 0x20; // 初始化為0x20(二進(jìn)制:00100000),第5位被設(shè)置 unsigned int mask = ~(1 << 5); // 創(chuàng)建一個(gè)掩碼,第5位為0,其他位為1 num &= mask; // 使用與操作清除第5位 printf("num: %u\n", num); // 輸出結(jié)果,應(yīng)該看到第5位被清除 return 0; }
示例3:檢查特定位
最后,假設(shè)我們想要檢查num的第5位是否被設(shè)置。我們可以使用以下代碼:
#include <stdio.h> int main() { unsigned int num = 0x20; // 初始化為0x20(二進(jìn)制:00100000),第5位被設(shè)置 unsigned int mask = 1 << 5; // 創(chuàng)建一個(gè)掩碼,第5位為1,其他位為0 int bitIsSet = (num & mask) != 0; // 使用與操作檢查第5位是否被設(shè)置 if (bitIsSet) { printf("The 5th bit is set.\n"); } else { printf("The 5th bit is not set.\n"); } return 0; }
三、字節(jié)提取與組裝實(shí)戰(zhàn)
- 字節(jié)提?。和ㄟ^(guò)右移和掩碼操作,可以提取整數(shù)的特定字節(jié)。
- 字節(jié)組裝:通過(guò)左移和按位或操作,可以將多個(gè)字節(jié)組合成一個(gè)整數(shù)。
字節(jié)提取示例
假設(shè)我們有一個(gè)32位無(wú)符號(hào)整數(shù)num
,其值為0x12345678
(十六進(jìn)制表示,二進(jìn)制為00010010 00110100 01010110 01111000
)。
提取低8位(最低字節(jié)):
unsigned char lowByte = (unsigned char)(num & 0xFF); printf("Low byte: 0x%02X\n", lowByte); // 輸出:Low byte: 0x78
這里,0xFF
是一個(gè)掩碼,其二進(jìn)制表示為11111111
。通過(guò)與操作&
,我們保留了num
的低8位,并將其他位清零。然后,我們將結(jié)果強(qiáng)制轉(zhuǎn)換為unsigned char
類型,以確保它是一個(gè)字節(jié)大小。
提取第二個(gè)字節(jié)(從0開始計(jì)數(shù)):
unsigned char secondByte = (unsigned char)((num >> 8) & 0xFF); printf("Second byte: 0x%02X\n", secondByte); // 輸出:Second byte: 0x56
首先,我們通過(guò)右移操作>> 8
將num
的所有位向右移動(dòng)8位,這樣原來(lái)的第二個(gè)字節(jié)就變成了新的低字節(jié)。然后,我們?cè)俅问褂?code>0xFF掩碼和與操作來(lái)提取這個(gè)新的低字節(jié)。
字節(jié)組裝示例
現(xiàn)在,假設(shè)我們有四個(gè)字節(jié)byte1 = 0x12
,byte2 = 0x34
,byte3 = 0x56
,byte4 = 0x78
,我們想要將它們組合成一個(gè)32位無(wú)符號(hào)整數(shù)。
將兩個(gè)字節(jié)組合成一個(gè)16位整數(shù):
unsigned char secondByte = (unsigned char)((num >> 8) & 0xFF); printf("Second byte: 0x%02X\n", secondByte); // 輸出:Second byte: 0x56
這里,我們首先通過(guò)左移操作<< 8
將byte1
的所有位向左移動(dòng)8位,為byte2
騰出空間。然后,我們使用按位或操作|
將byte1
(左移后的)和byte2
組合起來(lái)。
將四個(gè)字節(jié)組合成一個(gè)32位整數(shù):
unsigned short combined16 = (unsigned short)((byte1 << 8) | byte2); printf("Combined 16-bit: 0x%04X\n", combined16); // 輸出:Combined 16-bit: 0x1234
類似地,我們分別將byte1
、byte2
、byte3
向左移動(dòng)24位、16位和8位,然后將它們與byte4
通過(guò)按位或操作組合起來(lái)。
四、bitset 簡(jiǎn)介
bitset
是 C++ 標(biāo)準(zhǔn)庫(kù)中一個(gè)非常有用的類模板,它可以幫助我們高效地處理二進(jìn)制數(shù)據(jù)。通過(guò)使用 bitset
,我們可以方便地進(jìn)行位設(shè)置、重置、翻轉(zhuǎn)、檢查、獲取值以及位運(yùn)算等操作。此外,bitset
還提供了遍歷設(shè)置為 1 的位的功能,使得處理二進(jìn)制數(shù)據(jù)變得更加靈活和方便。
引入頭文件和定義 bitset
#include <bitset> std::bitset<8> myBitset;
常用操作
設(shè)置位:
使用 set()
函數(shù)可以將某個(gè)位設(shè)置為 1。例如:
myBitset.set(3); // 將第 4 個(gè)位(索引從 0 開始)設(shè)置為 1
重置位:
使用 reset()
函數(shù)可以將某個(gè)位設(shè)置為 0。如果調(diào)用時(shí)不帶參數(shù),則會(huì)重置整個(gè) bitset
。例如:
myBitset.reset(3); // 將第 4 個(gè)位重置為 0 myBitset.reset(); // 重置整個(gè) bitset
翻轉(zhuǎn)位:
使用 flip()
函數(shù)可以翻轉(zhuǎn)某個(gè)位或者整個(gè) bitset
的值。如果調(diào)用時(shí)不帶參數(shù),則會(huì)翻轉(zhuǎn)整個(gè) bitset
。例如:
myBitset.flip(3); // 翻轉(zhuǎn)第 4 個(gè)位 myBitset.flip(); // 翻轉(zhuǎn)整個(gè) bitset
檢查位:
使用 test()
函數(shù)可以檢查某個(gè)位是否為 1。例如:
bool isBitSet = myBitset.test(3); // 如果第 4 個(gè)位是 1,則返回 true,否則返回 false
獲取值:
使用 to_string()
函數(shù)可以獲取 bitset
的字符串表示。例如:
std::string bitsetString = myBitset.to_string(); // 返回一個(gè)表示 bitset 值的字符串
位運(yùn)算:
bitset
還支持一些位運(yùn)算操作,如按位與、按位或、按位異或等。例如:
std::bitset<8> anotherBitset("10101010"); myBitset &= anotherBitset; // 進(jìn)行按位與操作
遍歷位:
使用 find_first()
和 find_next()
函數(shù)可以遍歷設(shè)置為 1 的位。例如:
std::size_t pos = myBitset.find_first(); // 找到第一個(gè)設(shè)置為 1 的位的索引 while (pos != std::bitset<8>::npos) { // 處理設(shè)置為 1 的位 pos = myBitset.find_next(pos); // 找到下一個(gè)設(shè)置為 1 的位的索引 }
五、其他位操作技術(shù)
- 位旋轉(zhuǎn):涉及將整數(shù)的位向左或向右循環(huán)移動(dòng)??梢酝ㄟ^(guò)組合左移、右移和按位或操作來(lái)實(shí)現(xiàn)。
- 位計(jì)數(shù):計(jì)算一個(gè)整數(shù)中設(shè)置為1的位的數(shù)量??梢允褂弥鹞粰z查或使用更高效的算法(如Brian Kernighan算法)。
- 位查找:找到整數(shù)中第一個(gè)或最后一個(gè)設(shè)置為1的位的位置。可以使用逐位檢查或使用內(nèi)置函數(shù)(如
__builtin_ctz
或__builtin_clz
,取決于編譯器)。 - 位字段(Bit-fields):位字段是C和C++中一種特殊的數(shù)據(jù)結(jié)構(gòu),允許在結(jié)構(gòu)體中定義位級(jí)別的成員。雖然位字段在節(jié)省內(nèi)存空間方面非常有用,但跨平臺(tái)兼容性可能存在問(wèn)題,因?yàn)椴煌幾g器對(duì)位字段的布局和填充有不同的處理方式。因此,在使用位字段時(shí)需要謹(jǐn)慎,并確保在目標(biāo)平臺(tái)上進(jìn)行充分的測(cè)試。
到此這篇關(guān)于C++位操作實(shí)戰(zhàn)掩碼、提取與組裝的文章就介紹到這了,更多相關(guān)C++ 掩碼、提取與組裝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
OpenCV c++滑動(dòng)條的創(chuàng)建和使用代碼
滾動(dòng)條(Trackbar)在OpenCV中是非常方便的交互工具,它依附于特定的窗口而存在,下面這篇文章主要給大家介紹了關(guān)于OpenCV?c++滑動(dòng)條的創(chuàng)建和使用的相關(guān)資料,需要的朋友可以參考下2023-06-06c++獲取sqlite3數(shù)據(jù)庫(kù)表中所有字段的方法小結(jié)
本文給大家分享c++獲取sqlite3數(shù)據(jù)庫(kù)表中所有字段的三種常用方法,本文針對(duì)每一種方法給大家詳細(xì)介紹,需要的的朋友通過(guò)本文一起學(xué)習(xí)吧2016-11-11C語(yǔ)言中access/_access函數(shù)的使用實(shí)例詳解
本文通過(guò)實(shí)例代碼給大家介紹了C語(yǔ)言中access/_access函數(shù)的使用,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09C++入門教程之內(nèi)聯(lián)函數(shù)與extern?"C"詳解
C++中的內(nèi)聯(lián)函數(shù)與靜態(tài)函數(shù)靜態(tài)函數(shù)靜態(tài)函數(shù)的定義靜態(tài)函數(shù)又稱為內(nèi)部函數(shù),下面這篇文章主要給大家介紹了關(guān)于C++入門教程之內(nèi)聯(lián)函數(shù)與extern?"C"的相關(guān)資料,需要的朋友可以參考下2023-01-01C++實(shí)現(xiàn)LeetCode(136.單獨(dú)的數(shù)字)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(136.單獨(dú)的數(shù)字),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C語(yǔ)言中的內(nèi)聯(lián)函數(shù)(inline)與宏定義(#define)詳細(xì)解析
內(nèi)聯(lián)函數(shù)與宏本質(zhì)上是兩個(gè)不同的概念如果程序編寫者對(duì)于既要求快速,又要求可讀的情況下,則應(yīng)該將函數(shù)冠以inline2013-09-09