2013-06-27 197 views
1

假設我有一個uint16_t變量,我必須設置特定的位。如何設置特定位?

例子:

uint16_t field = 0;

這將意味着位均爲零:0000 0000 0000 0000

現在我得到一些價值觀,我需要設置在特定的位置。

val1=1; val2=2, val3=0, val4=4, val5=0;

如何設置的位的結構是以下

0|000| 0000| 0000 000|0 

val1應在左側的第一比特被設置。所以它只有一個或零。

val2應設置在接下來的三位。 val3接下來的四位。 val4上接下來的七位和val5最後一位。

,結果會是這樣: 1010 0000 0000 1000

我只發現瞭如何在一個特定的位,但不是「組」。 (shift或bitset)

有沒有人有一個想法如何解決這個問題?

+0

是結構固定或可變參數? – user1810087

+0

結構已修復 – baam

回答

7

有(至少)兩種基本方法。一個是創建一個結構與某些位字段:

struct bits { 
    unsigned a : 1; 
    unsigned b : 7; 
    unsigned c : 4; 
    unsigned d : 3; 
    unsigned e : 1; 
}; 

bits b; 

b.a = val1; 
b.b = val2; 
b.c = val3; 
b.d = val4; 
b.e = val5; 

要獲得16位的值,你可以(爲一例)創建結構的聯合與uint16_t。只是一個小問題:標準並不能保證在查看16位值時位域將以什麼順序結束。舉例來說,您可能需要將上面給出的順序顛倒過來,以獲得您真正想要的從最高位到最低位的順序(但更改編譯器可能會再次發生)。

其它明顯的可能性是使用移位和屏蔽把碎片一起成數:

int16_t result = val1 | (val2 << 1) | (val3 << 8) | (val4 << 12) | (val5 << 15); 

就目前而言,我已經假定每個輸入在正確的範圍內開始時(即,具有可以在所選擇的位數中表示的值)。如果有可能是錯誤的,你首先要掩蓋它到正確的位數。通常的做法是這樣的:

uint16_t result = input & ((1 << num_bits) - 1); 

如果您對那裏的數學好奇,它就像這樣工作。讓我們假設我們要確保輸入符合4位。移動1左邊4位產生00010000(二進制)。從中減去一個,然後清除所設置的一個位,並設置所有不太重要的位,對我們的例子給出00001111。這給了我們第一個最低有效位集合。當我們在該輸入和輸入之間執行按位AND時,輸入中設置的任何更高位都會在結果中清零。

+0

我試過它與位域。 編譯器不會改變,所以我可以使用這個解決方案。 我建立這樣一個聯合: 'struct bits { \t union { \t \t unsigned a:1; \t \t unsigned b:7; \t \t unsigned c:4; \t \t unsigned d:3; \t \t unsigned e:1; \t} vals; };' 並設置值 '\t位c; \t c.vals.a = val1; ...' 但我如何得到結果作爲一個完整的數字? – baam

+1

@baam:你想要兩個項目在聯合 - 結構和'uint16_t'。 'union {bits b; uint16_t v; };然後你會把數據寫到'u.b.whatever',但是檢索整個16位數字爲'u.v;' –

+0

這個工作很完美。非常感謝你! – baam

0
finalvle = 0; 
finalvle = (val1&0x01)<<15; 
finalvle += (val2&0x07)<<12; 
finalvle += (val3&0x0f)<<8 
finalvle += (val4&0xfe)<<1; 
finalvle += (val5&0x01); 
+0

沒有必要進行0賦值。 – xxbbcc

1

解決的辦法之一是設置一個K-位值起始於field作爲N個位:

uint16_t value_mask = ((1<<K)-1) << N; // for K=4 and N=3 will be 00..01111000 
field = field & ~value_mask; // zeroing according bits inside the field 
field = field | ((value << N) & value_mask); // AND with value_mask is for extra safety 

或者,如果你可以用它代替uint16_t結構,你可以使用Bit fields並讓編譯器爲您執行所有這些操作。

0

您可以使用按位或移位運算符來實現此目的。

利用shift <<爲「移動字節到左」:

int i = 1; // ...0001 
int j = i << 3 // ...1000 

然後可以使用按位或|把它在正確的地方,(假設你有你想的位全部爲零覆蓋)。

int k = 0; // ...0000 
k |= i // ...0001 
k |= j // ...1001 

編輯:請注意@ Inspired的答案還解釋了清零特定區域的位。它總體上解釋瞭如何正確實施它。

0

試試這個代碼:

uint16_t shift(uint16_t num, int shift) 
{ 
    return num | (int)pow (2, shift); 
} 

其中移位的位置,你想設置