如何在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++;
}
我认为这是正确的,但我如何按顺序显示每个位,以便我可以看到它们是否已正确设置?
感谢您的帮助。
答案 0 :(得分:1)
每8位后
for(int b=7;b>=0;b--)
{
printf("%d", (chararray[j] & (1<<b)) ? 1 : 0);
}
printf("\n");
答案 1 :(得分:1)
简单版本:
for (int i = 0; i < 40; i++) {
if (intarray[i] == 1) {
chararray[i/8] |= (1 << (i%8) );
}
}
应该可以(使用各种技巧,并依赖于一些&#34;实现定义&#34;行为)来创建一个一次执行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;
}
答案 2 :(得分:1)
如果我理解你的问题的两个部分(1)确认5 - unsigned char
整数数组40-element
值的-1 & 1
值的位设置; (2)输出每个5 - unsigned char
值的二进制表示,然后可以通过多种方式完成。为了set
每个值unsigned char
中的某个位,您只需按OR
当前值1
左移适当的金额设置问题。例如,要在3rd-bit
中设置unsigned char v = 0;
,只需设置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);
}
最后,您如何轻松查看每个无符号值的二进制表示以确认您的逻辑。与其他任何事情一样,你可以通过多种方式实现这一目标。对于一般测试,我找到一个简单的函数,返回二进制字符串的char *
表示,填充到所需的长度,或者更多,比任何其他方法更有用,因为它允许你保持正常单个printf
等格式化控件。
虽然unsigned
值不是100%必需,但大多数硬件同意4-bytes
构成int
和unsigned
。但是,由于可能存在变化,因此最好使用精确类型或使用简单的预处理程序指令来确定BITS_PER_LONG
的数量等。使用通用二进制打印例程来处理填充{{1值,一个简单的测试在32/64位机器之间是有用的。 e.g:
long unsigned
现在将所有部分放在一起并组成/* 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
示例使用/输出
输出值是针对您的5个#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;
}
数组元素中的每一个,显示根据unsigned char
和-1
的解释创建的十进制值s以及填充到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
只需要。 (当然根据自己的喜好调整输入和输出名称。)