[英]C Programming Setting Bits in Unsigned Char Array
如何在C中設置無符號字符數組的各個位? 如果我有
unsigned char chararray[5];
memset(chararray, ~0, 5);
我將所有位都設置為0。然后我需要將某些位設置為1。我知道此數組的每個元素中都有8位,所以如果我要在第二個元素中設置第3位,我相信我需要做類似的事情
chararray[1] |= (1 << 3);
我需要將數組的所有位設置為1以匹配另一個數組。 例如,我有一個包含1和-1的40元素整數數組。 如果索引i處的整數數組中的數字為1,我想將字符數組中的位設置為1,否則不將其保留為0。
這是我到目前為止的內容:
unsigned char chararray[5];
memset(array, ~0, 5);
int intarray[40]; //filled with random 1's and -1's
int j = 0;
for (int i = 0; i < 40; i++)
{
if (intarray[i] == 1)
{
if(j == 0)
chararray[0] |= (1 << i);
else
chararray[j] |= (1 << (i%8));
}
if(i % 8 == 0 && i > 0)
j++;
}
我相信這是正確的,但是我將如何按順序顯示每個位,以便查看它們是否已正確設置?
謝謝你的幫助。
每8位之后
for(int b=7;b>=0;b--)
{
printf("%d", (chararray[j] & (1<<b)) ? 1 : 0);
}
printf("\n");
簡單版本:
for (int i = 0; i < 40; i++) {
if (intarray[i] == 1) {
chararray[i/8] |= (1 << (i%8) );
}
}
應該有可能(使用各種技巧,並依靠一些“實現定義的”行為)來創建一個更快的版本,該版本一次執行8個整數(並且避免了很多分支,並且避免了預填充字符)零); 喜歡:
for (int i = 0; i < 40; i += 8) {
temp = ((unsigned int)intarray[i]) >> 31;
temp |= (((unsigned int)intarray[i+1]) >> 31) << 1;
temp |= (((unsigned int)intarray[i+2]) >> 31) << 2;
temp |= (((unsigned int)intarray[i+3]) >> 31) << 3;
temp |= (((unsigned int)intarray[i+4]) >> 31) << 4;
temp |= (((unsigned int)intarray[i+5]) >> 31) << 5;
temp |= (((unsigned int)intarray[i+6]) >> 31) << 6;
temp |= (((unsigned int)intarray[i+7]) >> 31) << 7;
chararray[i/8] = ~temp;
}
如果您的整數包含0和1(而不是-1和1),那會更好玩; 因為這樣您就可以擺脫像這樣的東西:
for (int i = 0; i < 40; i += 8) {
temp = intarray[i];
temp |= intarray[i+1] << 1;
temp |= intarray[i+2] << 2;
temp |= intarray[i+3] << 3;
temp |= intarray[i+4] << 4;
temp |= intarray[i+5] << 5;
temp |= intarray[i+6] << 6;
temp |= intarray[i+7] << 7;
chararray[i/8] = temp;
}
如果我理解您的問題的兩部分(1)確認您的位設置為-1 & 1
值的40-element
整數數組中的5 - unsigned char
值; (2)輸出5 - unsigned char
值中每個值的二進制表示,然后可以通過多種方式實現。 為了在每個unsigned char
值中set
一個位,您只需將當前值與1
按位“ OR
” 左移適當的值即可設置有爭議的位。 例如,將unsigned char v = 0;
的3rd-bit
設置為unsigned char v = 0;
,您只需設置v |= 1<<2;
可以使用嵌套循環蠻力方法來完成為所有5個無符號char元素設置位的幾種不同方法:
/* brute force nested loop approach */
for (i = 0; i < szarr; i++)
for (j = 0; j < CHAR_BIT; j++)
if (buf[i * CHAR_BIT + j] == 1) arr[i] |= (1 << j);
(其中szarr
是char arr[5] = {0};
sizeof *arr
char arr[5] = {0};
數組(或僅5
,而CHAR_BIT
( limits.h
)定義了char
的位數(通常為8
))
一種展開式方法,可提高效率(盡管當前大多數編譯器都將嘗試采用積極優化的展開式解決方案)。 可以更好地說明正在發生的過程:
/* unrolled loop setting all bits in each unsigned char per loop */
for (i = 0; i < szbuf; i+=8) {
if (buf[ i ] == 1) arr[i/8] |= 1;
if (buf[i+1] == 1) arr[i/8] |= (1 << 1);
if (buf[i+2] == 1) arr[i/8] |= (1 << 2);
if (buf[i+3] == 1) arr[i/8] |= (1 << 3);
if (buf[i+4] == 1) arr[i/8] |= (1 << 4);
if (buf[i+5] == 1) arr[i/8] |= (1 << 5);
if (buf[i+6] == 1) arr[i/8] |= (1 << 6);
if (buf[i+7] == 1) arr[i/8] |= (1 << 7);
}
最后,您如何輕松地查看每個無符號值的二進制表示形式以確認邏輯。 您可以像其他任何方式一樣來完成此操作。 對於一般測試,我發現一個簡單的函數可以返回二進制字符串的char *
表示形式,並填充為所需的長度,它比任何其他方法都有用,甚至比其他任何方法都有用,因為它允許您在其中保留常規格式控制單個printf
等。
盡管unsigned
值不是100%必需的,但是大多數硬件都認為4-bytes
構成一個int
和unsigned
。 但是,由於可能會有差異,所以最好使用精確類型或使用簡單的預處理程序指令來確定BITS_PER_LONG
的數量,等等。對於將處理填充long unsigned
值的通用二進制打印例程,這是一個簡單的測試在32/64位計算機之間很有幫助。 例如:
/* BITS_PER_LONG */
#if defined(__LP64__) || defined(_LP64)
# define BITS_PER_LONG 64
#else
# define BITS_PER_LONG 32
#endif
...
/** returns pointer to binary representation of 'v' zero padded to 'sz'.
* returns pointer to string contianing binary representation of
* unsigned 64-bit (or less ) value zero padded to 'sz' digits.
*/
char *binpad (const unsigned long v, const size_t sz)
{
static char s[BITS_PER_LONG + 1] = {0};
char *p = s + BITS_PER_LONG;
register size_t i;
for (i = 0; i < sz; i++)
*--p = (v>>i & 1) ? '1' : '0';
return p;
}
現在將所有部分放在一起,並組成一個由40-element
組成的-1
或1
值數組,以進行測試,您可以執行以下操作,並使用簡單的編譯器定義NESTED
表示要使用嵌套的蠻力進行構建循環版本,如果未給出定義,則使用展開版本:
#include <stdio.h>
/* CHAR_BIT */
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
/* BITS_PER_LONG */
#if defined(__LP64__) || defined(_LP64)
# define BITS_PER_LONG 64
#else
# define BITS_PER_LONG 32
#endif
char *binpad (const unsigned long v, const size_t sz);
int main (void){
unsigned char buf[] = { -1, -1, 1, -1, -1, -1, 1, 1,
-1, 1, -1, -1, -1, 1, 1, -1,
1, -1, -1, -1, 1, 1, -1, -1,
-1, -1, -1, 1, 1, -1, -1, -1,
-1, -1, 1, 1, -1, -1, -1, 1 };
unsigned char arr[5] = {0};
unsigned i, szarr = (unsigned) sizeof arr;
#ifdef NESTED
unsigned j;
/* brute force nested loop approach */
for (i = 0; i < szarr; i++)
for (j = 0; j < CHAR_BIT; j++)
if (buf[i * CHAR_BIT + j] == 1) arr[i] |= (1 << j);
#else
unsigned szbuf = (unsigned) sizeof buf;
/* unrolled loop setting all bits in each unsigned char per loop */
for (i = 0; i < szbuf; i+=8) {
if (buf[ i ] == 1) arr[i/8] |= 1;
if (buf[i+1] == 1) arr[i/8] |= (1 << 1);
if (buf[i+2] == 1) arr[i/8] |= (1 << 2);
if (buf[i+3] == 1) arr[i/8] |= (1 << 3);
if (buf[i+4] == 1) arr[i/8] |= (1 << 4);
if (buf[i+5] == 1) arr[i/8] |= (1 << 5);
if (buf[i+6] == 1) arr[i/8] |= (1 << 6);
if (buf[i+7] == 1) arr[i/8] |= (1 << 7);
}
#endif
for (i = 0; i < szarr; i++) /* validate the bit settings */
printf (" arr[%2u] : %3u (%s)\n",
i, arr[i], binpad (arr[i], CHAR_BIT));
return 0;
}
/** returns pointer to binary representation of 'v' zero padded to 'sz'.
* returns pointer to string contianing binary representation of
* unsigned 64-bit (or less ) value zero padded to 'sz' digits.
*/
char *binpad (const unsigned long v, const size_t sz)
{
static char s[BITS_PER_LONG + 1] = {0};
char *p = s + BITS_PER_LONG;
register size_t i;
for (i = 0; i < sz; i++)
*--p = (v>>i & 1) ? '1' : '0';
return p;
}
使用/輸出示例
輸出值是您的5個unsigned char
數組元素中每個元素的輸出值,它們顯示從-1
和1
的解釋創建的十進制值,以及填充到8-chars
該數字的二進制表示形式:
$ ./bin/array_uc_bits
arr[ 0] : 196 (11000100)
arr[ 1] : 98 (01100010)
arr[ 2] : 49 (00110001)
arr[ 3] : 24 (00011000)
arr[ 4] : 140 (10001100)
查看所有答案和所有方法,如果還有其他問題,請告訴我。
注意:如果您不熟悉在編譯時如何設置標簽定義(如NESTED
,則只需將其作為-D
-DNESTED
的選項傳遞即可,例如,在命令行中傳遞的-DNESTED
將觸發編譯嵌套的蠻力代碼。,例如
$ gcc -Wall -Wextra -Ofast -DNESTED -o bin/array_uc_bits_nest array_uc_bits.c
僅此而已。 (當然,可以根據您的喜好調整輸入和輸出名稱。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.