簡體   English   中英

C ++中的運行時位復制(位掩碼)

[英]Run-time bit copy (bit-masking) in C++

我手頭有一個問題並以一種方式解決了它,但是我不滿意如何解決它,因為它在每種情況下都不起作用。 解決方案必須在C ++(11)中。

我有一個char數組和一個int。 給定相對於數據的位偏移和長度(以位為單位)。 我想從數組中提取從offset到offset + length的位,並將它們存儲在外面。

char8_t data[8];
int32_t out;
int32_t offset;
int32_t length;

offset=24; length=4; 圖形 offset=24; length=4; offset=24; length=4;

偏移量和長度都僅在運行時可用。 因此,我想避免創建位掩碼。 我親自解決了此問題,方法是將整個數組轉換為int64_t,然后右移(64-offset-length),然后左移(64-length)。

out = (*(int64_t*)data) >> (64-offset-length) << (64-length);

問題是:如果我的陣列更長,將沒有原始數據來捕獲整個陣列。 我的解決方案不再起作用。 有更好的(縮放)方法嗎?

在理想的世界中,我可以創建一個具有一點偏移量的指針,但這不是C ++的理想世界。

我考慮過的替代方法是:通過遍歷數組並向左移動,在“ out”上加+ =。 毫不客氣!

我知道那里也有類似的問題,但是要么答案很差,要么對性能的影響很大。

首先,您的方法將取決於字節序,即系統是在各個8字節存儲塊的開頭還是結尾存儲最高有效字節。

其次,我將使用無符號數據類型,例如uchar8_t data[8]uint32_t ,以便正確處理位移和(自動)類型提升。

如果您確切知道data[8]的特定位置以及存儲順序,則可以按以下方式編寫它:

uint32_t out = data[0] + 256*data[1]; 
...

從而,您的“解碼器”將被拉緊到原始數據的順序/含義; 您的data可能會比最大的整數數據類型更長; 並且避免了因將帶符號的整數值移到帶符號的位上而導致的未定義行為。

如果偏移量不是8的倍數,即“值”不是從字節的開頭開始,則仍然可以使用移位操作來糾正此錯誤。 假設該值以2位的偏移量開始; 然后,您可以編寫:

uint32_t out = (data[0] >> 2) + (data[1] << 6) + (data[2] << (6+8))

但是-最終-您的目標將被限制為特定的位數,因為您特定平台上的C語言將為每種原始數據類型保證特定的大小, unsigned long long可能仍為64位。 此限制是由實現定義的,標准保證每種數據類型的位數最少。 這個限制是來自寄存器還是其他,您不知道-它的實現已定義。

您是否嘗試過std::vector<bool> 它是std::vectorstd::vector ,它結合了std::vector的動態大小和std::bitset緊湊性。

我將使用bitset作為臨時工具。 首先將一個循環中的復制字節對齊,然后執行位對齊。

unsigned startbit = offset;
unsigned startbyte = startbit / 8;
unsigned endbit = offset + length - 1;
unsigned endbyte = endbit / 8;

bitset<8*(sizeof(out) + 1)> align(0);
for(unsigned byte = endbyte; byte >= startbyte; --byte) { // byte align copy
// for(unsigned byte = startbyte; byte <= endbyte; ++byte) { // check endianess
    align <<= 8;
    align |= data[byte];
}
align >>= startbit % 8; // bit align
align &= ((1 << length) - 1); // mask

out = align.to_ullong();

我使用std::bitsetboost::dynamic_bitset表示二進制數據並對其進行操作。 如果長度固定,則std::bitset效果很好,否則boost::dynamic_bitset是一個不錯的選擇。 這樣,您可以使用重載的位運算符提取位:

#include <boost/dynamic_bitset.hpp>

using boost::dynamic_bitset;

dynamic_bitset<unsigned char> extract(unsigned char* first, unsigned char* last, int offset, int length) {
   dynamic_bitset<unsigned char> bits(first, last);

   bits >>= bits.size() - (offset  + length);
   bits.resize(length);

   return bits;
}

因此,而不是int32_t out; 您可以使用dynamic_bitset<>高效地保存任意位長度的值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM