2010-03-06 107 views
3

在C/C++中,是否有一種簡單的方法將位運算符(特別是左/右移)應用於動態分配內存?C/C++:動態分配內存上的按位運算符

例如,假設我這樣做:

unsigned char * bytes=new unsigned char[3]; 
bytes[0]=1; 
bytes[1]=1; 
bytes[2]=1; 

我想辦法做到這一點:

bytes>>=2; 

(當時的 '字節' 將具有以下值) :

bytes[0]==0 
bytes[1]==64 
bytes[2]==64 

爲什麼值應該是這樣:

分配之後,字節是這樣的:

[00000001][00000001][00000001] 

但我正在尋找治療字節位中的一個長字符串,像這樣:

[000000010000000100000001] 

兩個右移將導致位看起來像這樣:

[000000000100000001000000] 

並最終看起來像這樣分離回3個字節​​(因此爲0,64,64)時:

[00000000][01000000][01000000] 

任何想法?我應該做一個結構/類並重載適當的操作符?編輯:如果是這樣,任何提示如何進行?注意:我正在尋找一種方法來自己實施(有一些指導)作爲學習體驗。

+0

你會期望這個每個單獨移動?或者將一個字節的位傳送到下一個字節? – 2010-03-06 23:03:50

+0

你的意思是你想要轉移跨越你訪問的字節的邊界嗎?我假設你也希望能夠做到這一點,比如說4個字節,這對於整型和輪班來說可能是安全的。 – 2010-03-06 23:04:08

+0

我編輯了我的帖子,以顯示轉換後的值。對不起,原來缺乏清晰度。 (@John,我希望這會將位從一個字節傳送到下一個字節) – Cam 2010-03-06 23:05:18

回答

2

正如John Knoeller所建議的那樣,我打算假定您需要從一個字節傳輸到下一個字節。

這裏的要求是不夠的。您需要指定相對於字節順序的位順序 - 當最低有效位從一個字節中溢出時,確實轉到下一個較高或下一個較低字節。

雖然您描述的是過去常常用於圖形編程的東西。您基本上已經描述了一種單色位圖水平滾動算法。

假設「右」意味着更高的地址,但較少顯著位(即匹配的正常書寫約定兩者)的單位的移位將是類似...

void scroll_right (unsigned char* p_Array, int p_Size) 
{ 
    unsigned char orig_l = 0; 
    unsigned char orig_r; 

    unsigned char* dest = p_Array; 

    while (p_Size > 0) 
    { 
    p_Size--; 

    orig_r = *p_Array++; 
    *dest++ = (orig_l << 7) + (orig_r >> 1); 

    orig_l = orig_r; 
    } 
} 

適應可變的代碼換檔尺寸不應該是一個大問題。有明顯的優化機會(例如,一次執行2,4或8個字節),但我會把它留給你。

然而,要向左移動,您應該使用一個單獨的循環,該循環應該從最高地址開始並向下運行。

如果要「按需」擴展,請注意orig_l變量包含上面的最後一個字節。要檢查溢出,請檢查(orig_l < < 7)是否爲非零。如果你的字節在std :: vector中,那麼在兩端插入應該沒問題。

編輯我應該說 - 優化一次處理2,4或8個字節會產生對齊問題。例如,當從未對齊的字符數組中讀取兩個字節的字時,最好先進行奇數字節讀取,以便稍後的字讀取全部在偶數地址上,直到循環結束。

在x86上這不是必須的,但它要快得多。在一些處理器上是必要的。只需根據基地址(地址& 1),(地址& 3)或(地址& 7)來開關一個開關,以便在循環開始前處理前幾個字節。您還需要特殊情況下主循環後的尾部字節。

+0

完美,謝謝!我會把它們放在一個向量中;不知道爲什麼我沒有想到:) 真的有幫助的答案! – Cam 2010-03-06 23:25:29

2
  • 從訪問解耦分配/存取器
  • 接下來,看看是否像bitset一個標準集裝箱可以做的工作適合你
  • 否則退房boost::dynamic_bitset
  • 如果所有的失敗,推出自己的類

粗糙例如:

typedef unsigned char byte; 

byte extract(byte value, int startbit, int bitcount) 
{ 
    byte result; 
    result = (byte)(value << (startbit - 1)); 
    result = (byte)(result >> (CHAR_BITS - bitcount)); 
    return result; 
} 

byte *right_shift(byte *bytes, size_t nbytes, size_t n) { 
    byte rollover = 0; 
    for (int i = 0; i < nbytes; ++i) { 
    bytes[ i ] = (bytes[ i ] >> n) | (rollover < n); 
    byte rollover = extract(bytes[ i ], 0, n); 
    } 
    return &bytes[ 0 ]; 
} 
+0

這看起來很酷。然而,作爲一種學習體驗,我很樂意製作我自己的作品。另外,我特別喜歡它能夠根據需求擴大(大小)。 – Cam 2010-03-06 23:11:33

+0

@incrediman:請注意,boost :: dynamic_bitset對象的大小可以在運行時指定。如果你熱衷於學習,我建議看看他們的實現並推出你自己的(只有你需要的功能)。 – dirkgently 2010-03-06 23:14:10

0

運算符重載是語法糖。這實際上只是一種調用函數並傳遞字節數組而不需要它的方式看起來就像您正在調用函數一樣。

所以我寫此功能

unsigned char * ShiftBytes(unsigned char * bytes, size_t count_of_bytes, int shift); 

然後,如果你想在一個操作符重載來包裝這件事,以使其更容易使用,或者因爲你只是喜歡這種語法,你可以做啓動也是如此。或者你可以調用這個函數。

+0

您只能在用戶定義的類型上使用運算符重載,本示例爲'unsigned char *'。海報必須定義一個類來表示數據結構。 – 2010-03-06 23:22:15

+0

@David:良好的捕獲,無符號字符,不是字節。但我不確定我是否明白你的意思。爲了實現超載,你仍然需要一個可以進行字節轉換的函數。 – 2010-03-06 23:25:10

+0

'unsigned char'對於表示一個字節很有用,但它不是用戶定義的類型。你不能定義'unsigned char * :: operator >>(int)',它必須是'Bitarray :: operator >>(int)'。中間有一步你錯過了,我可能會得到有關海報細節的肛門。 – 2010-03-07 03:32:32

1

這是我會怎麼做它的兩個字節:

unsigned int rollover = byte[0] & 0x3; 
byte[0] >>= 2; 

byte[1] = byte[1] >> 2 | (rollover << 6); 

從那裏,你可以概括成一個圈這爲n個字節。爲了靈活性,您需要生成幻數(0x3和6),而不是硬編碼它們。

1

我會考慮類似的措施:

#define number_of_bytes 3 

template<size_t num_bytes> 
union MyUnion 
{ 
    char   bytes[num_bytes]; 
    __int64   ints[num_bytes/sizeof(__int64) + 1]; 
}; 

void main() 
{ 
    MyUnion<number_of_bytes> mu; 
    mu.bytes[0] = 1; 
    mu.bytes[1] = 1; 
    mu.bytes[2] = 1; 
    mu.ints[0] >>= 2; 
} 

與它剛玩。你會得到我相信的想法。