簡體   English   中英

無符號字符數組中的C編程設置位

[英]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);

(其中szarrchar arr[5] = {0}; sizeof *arr char arr[5] = {0};數組(或僅5 ,而CHAR_BITlimits.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構成一個intunsigned 但是,由於可能會有差異,所以最好使用精確類型或使用簡單的預處理程序指令來確定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組成的-11值數組,以進行測試,您可以執行以下操作,並使用簡單的編譯器定義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數組元素中每個元素的輸出值,它們顯示從-11的解釋創建的十進制值,以及填充到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.

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