我正在学习 C/C++ 编程并且遇到过“位数组”或“位向量”的用法。无法理解他们的目的吗?这是我的疑问 -

  1. 它们用作布尔标志吗?
  2. 可以一个用吗 int 数组代替?(当然更多的记忆,但是..)
  3. 位屏蔽的概念是什么?
  4. 如果位掩码是简单的位操作以获得适当的标志,那么如何为它们编程?在 head 中执行此操作以查看与十进制数字相对应的标志是什么,是不是很困难?

我正在寻找应用程序,以便我可以更好地理解。对于例如 -

问。 您将获得一个包含范围(1 到 100 万)整数的文件。有一些重复,因此缺少一些数字。找到最快的找到丢失数字的方法?

对于上述问题,我已阅读告诉我使用位数组的解决方案。如何将每个整数存储在一位中?

有帮助吗?

解决方案

我认为您对数组和数字感到困惑,特别是操作二进制数意味着什么。

我将通过例子来讨论这个问题。假设您有许多错误消息,并且希望将它们作为函数的返回值返回。现在,您可以将错误标记为 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

我相信你知道 and 是如何工作的,或者可以从上面的数字中推断出来 - 如果任何两个数字都是 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 的幂)分配给特定含义,并应用二进制运算来推断它们是否已设置,然后对它们进行操作。

我还应该补充一点,二进制运算在思想上与计算机的底层电子器件很接近。想象一下,如果位字段对应于各种电路的输出(是否承载电流)。通过使用所述电路的足够组合,您可以...一台电脑。

其他提示

关于位数组的用法:

如果您知道“只有”100 万个数字 - 您可以使用 100 万位的数组。一开始,所有位都为零,每次读取数字时 - 使用该数字作为索引,并将该索引中的位更改为 1(如果它还不是 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 - 这些是缺失的数字

顺便说一句,当然你可以使用整数而不是位,但它可能需要(取决于系统)32倍的内存

西万

位数组或位向量可以作为 布尔值数组. 。通常,布尔变量至少需要一个字节存储,但在位数组/向量中只需要一位。如果您有大量此类数据,这会很方便,因此可以节省大量内存。

另一种用法是如果你有 不完全符合标准变量的数字 大小为 8、16、32 或 64 位。您可以通过这种方式将一个由 4 位、一个 2 位和一个 10 位组成的数字存储到 16 位的位向量中。通常您必须使用 3 个大小为 8,8 和 16 位的变量,因此您只浪费了 50% 的存储空间。

但所有这些用途在业务应用程序中很少使用,在通过接口连接驱动程序时经常使用 pinvoke/互操作 功能和做事 低级编程.

位向量的位数组用作从位置到某个位值的映射。是的,它与 Bool 数组基本相同,但典型的 Bool 实现是一到四个字节长,并且使用了太多空间。

通过使用字数组和二进制掩码操作以及移位来存储和检索它们,我们可以更有效地存储相同数量的数据(更少的总体内存使用,更少的内存访问,更少的缓存未命中,更少的内存页面交换)。访问各个位的代码仍然非常简单。

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);
                    }
                }
            }
        }
    }
}

它用于位标志存储,以及解析不同的二进制协议字段,其中 1 个字节被划分为多个位字段。它广泛用于 TCP/IP、ASN.1 编码、OpenPGP 数据包等协议中。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top