如何在C中实现位集

如何在C中实现位集,c,pointers,struct,C,Pointers,Struct,下面创建和使用位集的代码来自以下教程。我重写这段代码是为了学习和理解更多关于C结构和指针的知识 #include <stdio.h> #include <stdlib.h> #define WORDSIZE 32 #define BITS_WORDSIZE 5 #define MASK 0x1f // Create a bitset int initbv(int **bv, int val) { *bv = calloc(val/WORDSIZE + 1, siz

下面创建和使用位集的代码来自以下教程。我重写这段代码是为了学习和理解更多关于C结构和指针的知识

#include <stdio.h>
#include <stdlib.h>

#define WORDSIZE 32
#define BITS_WORDSIZE 5
#define MASK 0x1f

// Create a bitset
int initbv(int **bv, int val) {
  *bv = calloc(val/WORDSIZE + 1, sizeof(int));
  return *bv != NULL;
}

// Place int 'i' in the biset
void set(int bv[], int i) {
  bv[i>>BITS_WORDSIZE] |= (1 << (i & MASK));
}

// Return true if integer 'i' is a member of the bitset
int member(int bv[], int i) {
  int boolean = bv[i>>BITS_WORDSIZE] & (1 << (i & MASK));
  return boolean;
}

int main() {
  int *bv, i;

  int s1[] = {32, 5, 0};
  int s2[] = {32, 4, 5, 0};

  initbv(&bv, 32);

  // Fill bitset with s1
  for(i = 0; s1[i]; i++) {
    set(bv, s1[i]);
  }

  // Print intersection of bitset (s1) and s2
  for(i = 0; s2[i]; i++) {
    if(member(bv, s2[i])) {
      printf("%d\n", s2[i]);
    }
  }

  free(bv);
  return 0;
}
#包括
#包括
#定义字号32
#定义位\u字号5
#定义掩码0x1f
//创建一个位集
int initbv(int**bv,int val){
*bv=calloc(val/WORDSIZE+1,sizeof(int));
返回*bv!=NULL;
}
//将int“i”放入biset中
无效集(int bv[],int i){
bv[i>>BITS_WORDSIZE]|=(1>BITS_WORDSIZE]&(1bv=calloc(size/WORDSIZE+1,sizeof(int));
返回集;
}
/*将项添加到位集中*/
int位集_添加(结构位集*此,int项){

返回此->bv[item>>BITS_WS]|=(1 bv[item>>BITS_WS]&(1从
bitset_查找返回的值应视为二进制真值(即:否为是),不是数值。如果它是零,则不设置位;如果它不是零,则设置位。实际上,该函数应该返回
boolean!=0
,这将强制其值为零或一,一个真正的布尔值,而不是当前的零或任何值(实际上
(1)这不是教程,充其量只是误导性示例

首先,使用无符号类型。我建议
无符号long
(出于各种原因,它们都不重要)。
头文件定义常量
CHAR\u-BIT
,任何无符号整数类型中可以使用的位数总是
CHAR\u-BIT*sizeof(unsigned\u-type)

其次,通过向结构中添加大小信息,可以动态调整位图(或有序位集)的大小

上述情况归结为:

#include <stdlib.h>
#include <limits.h>

#define ULONG_BITS (CHAR_BIT * sizeof (unsigned long))

typedef struct {
    size_t         ulongs;
    unsigned long *ulong;
} bitset;

#define BITSET_INIT { 0, NULL }

void bitset_init(bitset *bset)
{
    if (bset) {
        bset->ulongs = 0;
        bset->ulong  = NULL;
    }
}

void bitset_free(bitset *bset)
{
    if (bset) {
        free(bset->ulong);
        bset->ulongs = 0;
        bset->ulong  = NULL;
    }
}

/* Returns: 0 if successfully set
           -1 if bs is NULL
           -2 if out of memory. */
int bitset_set(bitset *bset, const size_t bit)
{
    if (bset) {
        const size_t  i = bit / ULONG_BITS;

        /* Need to grow the bitset? */
        if (i >= bset->ulongs) {
            const size_t   ulongs = i + 1; /* Use better strategy! */
            unsigned long *ulong;
            size_t         n = bset->ulongs;

            ulong = realloc(bset->ulong, ulongs * sizeof bset->ulong[0]);
            if (!ulong)
                return -2;

            /* Update the structure to reflect the changes */
            bset->ulongs = ulongs;
            bset->ulong  = ulong;

            /* Clear the newly acquired part of the ulong array */
            while (n < ulongs)
                ulong[n++] = 0UL;
        }

        bset->ulong[i] |= 1UL << (bit % ULONG_BITS);

        return 0;
    } else
        return -1;
}

/* Returns: 0 if SET
            1 if UNSET
           -1 if outside the bitset */
int bitset_get(bitset *bset, const size_t bit)
{
    if (bset) {
        const size_t  i = bit / ULONG_BITS;

        if (i >= bset->ulongs)
            return -1;

        return !(bset->ulong[i] & (1UL << (bit % ULONG_BITS)));
    } else
        return -1;
}
它仅对设置的位返回1,对设置之外的位返回0

请注意
!!
。它只是两个not运算符,没有什么奇怪的;使其成为not not运算符。
!!如果
x
为零,则x
为0;如果
x
为非零,则为1

(单个not运算符
!x
,如果
x
为零,则生成1;如果
x
为非零,则生成0。不应用两次,则生成上文解释的not not。)

要使用上述方法,请尝试以下操作:

int main(void)
{
    bitset train = BITSET_INIT;

    printf("bitset_get(&train, 5) = %d\n", bitset_get(&train, 5));

    if (bitset_set(&train, 5)) {
        printf("Oops; we ran out of memory.\n");
        return EXIT_FAILURE;
    } else
        printf("Called bitset_set(&train, 5) successfully\n");

    printf("bitset_get(&train, 5) = %d\n");

    bitset_free(&train);

    return EXIT_SUCCESS;
}
因为我们对正在运行的硬件或系统不做任何假设(除非我在某个地方出错了;如果你注意到了,请在评论中告诉我,这样我就可以修复我的错误!),而且只有C标准说我们可以依赖的东西,这应该适用于任何可以使用符合标准的编译器编译代码的东西。Windows、Linux、BSDs、旧Unix、macOS和其他


通过一些更改,它甚至可以在微控制器上工作。我不确定是否所有开发库都有
realloc()
;甚至
malloc())
可能不可用。除此之外,在32位ARMs等设备上,这应该可以正常工作;在8位AVR等设备上,最好使用
无符号字符
字符
,因为它们倾向于模拟更大的类型,而不是在硬件上支持它们。(上面的代码可以工作,但速度会慢一些。)

这是调试器可以提供帮助的地方。1)如果不知道其负面影响,请不要使用带符号的整数进行位移位/掩蔽。2)如果希望使用固定宽度类型进行修复,请使用固定宽度类型。3)
WORDSIZE
sizeof(int)
之间没有关系如果那是从那一刻开始的,忘掉它,找一个更好的。。。
int bitset_get(bitset *bset, const size_t bit)
{
    if (bset) {
        const size_t  i = bit / ULONG_BITS;

        if (i >= bset->ulongs)
            return 0;

        return !!(bset->ulong[i] & (1UL << (bit % ULONG_BITS)));
    } else
        return 0;
}
int main(void)
{
    bitset train = BITSET_INIT;

    printf("bitset_get(&train, 5) = %d\n", bitset_get(&train, 5));

    if (bitset_set(&train, 5)) {
        printf("Oops; we ran out of memory.\n");
        return EXIT_FAILURE;
    } else
        printf("Called bitset_set(&train, 5) successfully\n");

    printf("bitset_get(&train, 5) = %d\n");

    bitset_free(&train);

    return EXIT_SUCCESS;
}