C 编程设置 Unsigned Char 数组中的位
C Programming Setting Bits in Unsigned Char Array
如何在 c 语言中设置 unsigned char 数组的各个位?如果我有
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) );
}
}
应该有可能(使用各种技巧,并依靠一点点 "implementation defined" 行为)创建一个更快的版本,一次处理 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) 从 40-element
整数数组 -1 & 1
值中确认你对 5 - unsigned char
值的位设置; (2) 输出每个 5 - unsigned char
值的二进制表示,然后可以通过多种方式完成。为了在每个 unsigned char
值中 set
位,你只需按位 OR
当前值与 1
左移 的适当的数量来设置有问题的位。例如要在 unsigned char v = 0;
中设置 3rd-bit
,您只需设置 v |= 1<<2;
可以使用嵌套循环蛮力方法完成为所有 5 个 unsigned 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
是 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);
}
最后,您如何轻松查看每个无符号值的二进制表示以确认您的逻辑。与其他任何事情一样,您可以如何实现这一点。对于一般测试,我发现一个简单的函数,它 returns 二进制字符串的 char *
表示,填充到所需的长度,as 或更多,比它允许的任何其他方法都有用您可以在单个 printf
等范围内保留正常的格式控制。
虽然 unsigned
值并非 100% 必要,因为大多数硬件都同意 4-bytes
构成 int
和 unsigned
。但是,由于可能存在变化,因此最好使用精确类型或使用简单的预处理器指令来确定 BITS_PER_LONG
的数量等。使用将处理填充 [=42] 的通用二进制打印例程=] 值,一个简单的测试在 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;
}
例子Use/Output
输出值适用于 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
在命令行上传递将触发编译嵌套暴力代码,例如
$ gcc -Wall -Wextra -Ofast -DNESTED -o bin/array_uc_bits_nest array_uc_bits.c
是所有需要的。 (当然可以根据自己的喜好调整输入和输出名称。)
如何在 c 语言中设置 unsigned char 数组的各个位?如果我有
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) );
}
}
应该有可能(使用各种技巧,并依靠一点点 "implementation defined" 行为)创建一个更快的版本,一次处理 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) 从 40-element
整数数组 -1 & 1
值中确认你对 5 - unsigned char
值的位设置; (2) 输出每个 5 - unsigned char
值的二进制表示,然后可以通过多种方式完成。为了在每个 unsigned char
值中 set
位,你只需按位 OR
当前值与 1
左移 的适当的数量来设置有问题的位。例如要在 unsigned char v = 0;
中设置 3rd-bit
,您只需设置 v |= 1<<2;
可以使用嵌套循环蛮力方法完成为所有 5 个 unsigned 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
是 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);
}
最后,您如何轻松查看每个无符号值的二进制表示以确认您的逻辑。与其他任何事情一样,您可以如何实现这一点。对于一般测试,我发现一个简单的函数,它 returns 二进制字符串的 char *
表示,填充到所需的长度,as 或更多,比它允许的任何其他方法都有用您可以在单个 printf
等范围内保留正常的格式控制。
虽然 unsigned
值并非 100% 必要,因为大多数硬件都同意 4-bytes
构成 int
和 unsigned
。但是,由于可能存在变化,因此最好使用精确类型或使用简单的预处理器指令来确定 BITS_PER_LONG
的数量等。使用将处理填充 [=42] 的通用二进制打印例程=] 值,一个简单的测试在 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;
}
例子Use/Output
输出值适用于 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
在命令行上传递将触发编译嵌套暴力代码,例如
$ gcc -Wall -Wextra -Ofast -DNESTED -o bin/array_uc_bits_nest array_uc_bits.c
是所有需要的。 (当然可以根据自己的喜好调整输入和输出名称。)