我正在学习C / C ++编程&遇到过'比特数组'或'比特向量'的用法。我无法理解他们的目的?这是我的疑惑 -
int
数组吗? (当然更多的记忆,但是..)我正在寻找应用程序,以便我能更好地理解。对于Eg -
问。您将获得一个包含范围(1到1百万)范围内整数的文件。有一些重复,因此缺少一些数字。找到找到失踪的最快方法 号码?
对于上述问题,我已阅读解决方案,告诉我使用位数组。如何将每个整数存储一下?
答案 0 :(得分:14)
我认为你对数组和数字感到困惑,特别是操纵二进制数字意味着什么。
我将以身作则。假设您有许多错误消息,并且希望以函数的返回值返回它们。现在,您可以标记您的错误1,2,3,4 ...这对您的想法有意义,但是如果只给出一个数字,您如何计算出发生了哪些错误?
现在,尝试标记错误1,2,4,8,16 ...基本上增加2的幂。为什么这样做?好吧,当你在2号基地工作时,你正在操纵一个像00000000
这样的数字,其中每个数字对应2的幂乘以它从右边的位置。因此,假设出现错误1,4和8。那么,那可以表示为00001101
。相反,第一个数字= 1 * 2 ^ 0,第三个数字1 * 2 ^ 2和第四个数字1 * 2 ^ 3。将它们全部添加为13。
现在,我们可以通过应用位掩码来测试是否发生了这样的错误。例如,如果您想在错误8
发生时计算出来,请使用8 = 00001000
的位表示。现在,为了提取是否发生了错误,请使用二进制文件,如下所示:
00001101
& 00001000
= 00001000
我确定你知道如何工作或者可以从上面推断它 - 数字工作,如果任何两位数都是1,结果是1,否则它是0。
现在,在C:
int func(...)
{
int retval = 0;
if ( sometestthatmeans an error )
{
retval += 1;
}
if ( sometestthatmeans an error )
{
retval += 2;
}
return retval
}
int anotherfunc(...)
{
uint8_t x = func(...)
/* binary and with 8 and shift 3 plaes to the right
* so that the resultant expression is either 1 or 0 */
if ( ( ( x & 0x08 ) >> 3 ) == 1 )
{
/* that error occurred */
}
}
现在,实用性。当内存稀疏且协议没有冗长的冗长的xml等时,通常将字段划分为如此多的位宽。在该字段中,您将各种位(标志,2的幂)分配给某个含义,并应用二进制运算来推断它们是否已设置,然后对它们进行操作。
我还应该补充说,二进制操作与计算机的底层电子设备关系密切。想象一下,如果位字段对应于各种电路的输出(携带电流与否)。通过使用所述电路的足够组合,您可以制作一台计算机。
答案 1 :(得分:9)
关于bits数组的用法:
如果您知道“只有”100万个数字 - 您使用的是100万位的数组。在开始时,所有位都为零,每次读取一个数字时 - 使用此数字作为索引,并将此索引中的位更改为1(如果已经不是一个)。
读完所有数字后 - 缺少的数字是数组中零的索引。
例如,如果我们只有0到4之间的数字,则数组在开头看起来像这样:0 0 0 0 0。 如果我们读数字:3,2,2 数组看起来像这样:阅读3 - > 0 0 0 1 0.读3(再次) - > 0 0 0 1 0.读2 - > 0 0 1 1 0.检查零的索引:0,1,4 - 这些是缺失的数字
BTW,当然你可以使用整数而不是位但它可能需要(取决于系统)32次内存斯万
答案 2 :(得分:3)
比特矢量的比特数组用作从位置到某个比特值的映射。是的,它与Bool数组基本相同,但典型的Bool实现长度为1到4个字节,并且占用的空间太大。
我们可以通过使用单词数组和二进制掩码操作来更有效地存储相同数量的数据,并转换来存储和检索它们(使用的内存更少,内存访问更少,缓存未命中,内存页交换更少) 。访问各个位的代码仍然非常简单。
还有一些用C语言内置的位字段支持(你可以写int i:1;
之类的东西说“只消耗一位”),但它不适用于数组,你对整体结果的控制较少(实现细节取决于编译器和对齐问题)。
以下是回答“搜索缺失号码”问题的可能方法。我将int大小固定为32位以保持简单,但可以使用sizeof(int)编写它以使其可移植。并且(取决于编译器和目标处理器)代码只能使用>> 5
代替/ 32
和& 31
而不是% 32
来加快速度,但这只是为了给出这个想法。
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
int main(){
/* put all numbers from 1 to 1000000 in a file, except 765 and 777777 */
{
printf("writing test file\n");
int x = 0;
FILE * f = fopen("testfile.txt", "w");
for (x=0; x < 1000000; ++x){
if (x == 765 || x == 777760 || x == 777791){
continue;
}
fprintf(f, "%d\n", x);
}
fprintf(f, "%d\n", 57768); /* this one is a duplicate */
fclose(f);
}
uint32_t bitarray[1000000 / 32];
/* read file containing integers in the range [1,1000000] */
/* any non number is considered as separator */
/* the goal is to find missing numbers */
printf("Reading test file\n");
{
unsigned int x = 0;
FILE * f = fopen("testfile.txt", "r");
while (1 == fscanf(f, " %u",&x)){
bitarray[x / 32] |= 1 << (x % 32);
}
fclose(f);
}
/* find missing number in bitarray */
{
int x = 0;
for (x=0; x < (1000000 / 32) ; ++x){
int n = bitarray[x];
if (n != (uint32_t)-1){
printf("Missing number(s) between %d and %d [%x]\n",
x * 32, (x+1) * 32, bitarray[x]);
int b;
for (b = 0 ; b < 32 ; ++b){
if (0 == (n & (1 << b))){
printf("missing number is %d\n", x*32+b);
}
}
}
}
}
}
答案 3 :(得分:3)
位数组或位向量可以作为布尔值数组。通常,布尔变量至少需要一个字节存储,但在位数组/向量中只需要一位。 如果您有大量此类数据,这样可以节省大量内存。
另一种用法是,如果您的数字不完全适合标准变量,其大小为8,16,32或64位。你可以通过这种方式存储一个16位的位向量,一个由4位组成的数字,一个是2位,一个是10位。通常你必须使用大小为8,8和16位的3个变量,所以你只有50%的存储浪费。
但所有这些用途很少用于业务应用程序,通常在通过 pinvoke / interop 函数连接驱动程序并执行低级编程时使用。
答案 4 :(得分:2)
用于位标志存储,以及用于解析不同的二进制协议字段,其中1字节被分成多个位字段。这在TCP / IP等协议中广泛使用,最高可达ASN.1编码,OpenPGP数据包等。