C

时间:2017-07-07 19:12:28

标签: c arrays struct bit huffman-code

我注意到C中的单个位没有内置结构。有(无符号)char和int,它们是8位(一个字节),long是64+位,所以on(uint64_t,bool ...)

我在编写一个霍夫曼树时遇到了这个问题,并且某些字符的编码不一定是8位长(如00101),因此没有有效的方法来存储编码。我必须找到临时解决方案,如字符串或布尔数组,但这需要更多的内存。

但无论如何,我的问题更为笼统:是否有一种存储位的数组或某种用户定义结构的好方法?我在网上搜索了一个,但最小的结构似乎是8位(一个字节)。我尝试了诸如int a : 1之类的东西,但它没有用。我读到了有关字段的内容,但它们并不能简单地实现我想做的事情。我知道在C ++中已经有人问过这个问题,如果有一个结构用于单个位,但大多数情况下我想知道什么是在C中存储编码如00101的最节省内存的方法。

4 个答案:

答案 0 :(得分:5)

如果您主要对一次访问一个位感兴趣,可以使用unsigned char数组并将其视为位数组。例如:

unsigned char array[125];

假设每字节8比特,这可以被视为1000比特的数组。前16个逻辑上看起来像这样:

     ---------------------------------------------------------------------------------
byte |                   0                   |              1                        |
     ---------------------------------------------------------------------------------
bit  |  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 | 10 | 11 | 12 | 13 | 14 | 15 |
     ---------------------------------------------------------------------------------

假设您想使用位b。然后,您可以执行以下操作:

读取位b

value = (array[b/8] & (1 << (b%8)) != 0;

设置位b

array[b/8] |= (1 << (b%8));

清除位b

array[b/8] &= ~(1 << (b%8));

将位数除以8可获得相关字节。类似地,将位数修改为8会为您提供该字节内的相关位。然后,您将值1移位一位,以便为您提供必要的位掩码。

虽然这里有整数除法和模数,但被除数是2的幂,所以任何体面的编译器都应该用位移/掩码代替它们。

答案 1 :(得分:4)

  

我注意到C中的单个位没有内置结构。

这是事实,它是有道理的,因为基本上没有机器具有位可寻址的内存。

  

但无论如何,我的问题更为笼统:是否有一个好的存储方式   一个位数组,或某种用户定义的结构?

通常使用unsigned char或其他无符号整数类型或其数组。除此之外,您还需要一些屏蔽和移位来设置或读取各个位的值。

  我仔细搜索了一下   web for one但最小的结构似乎是8位(一个字节)。

从技术上讲,最小的可寻址存储单元([[un] signed] char)可能大于8位,但你不太可能看到它。

  

我尝试了诸如int a:1之类的东西,但它没有用。我读了一下   但他们并没有完全达到我想做的目的。

位字段只能作为结构成员出现。包含这样一个位域的结构对象的大小仍然是char大小的倍数,因此不能很好地映射到位数组或其中的任何部分。

  

我   知道问题已经在C ++中被问及这个问题   是一个单位的结构,但大多数我想具体知道   什么是存储编码的最节省内存的方法   在C中为00101。

如果您需要一个位模式一个单独的位计数 - 例如,如果位存储对象中的某些位实际上不重要 - 那么您需要一个单独的数据有效位数。如果你想要一个小但可变数量的位的数据结构,那么你可能会采用以下几点:

struct bit_array_small {
    unsigned char bits;
    unsigned char num_bits;
};

当然,您可以通过为bits成员和num_bits成员选择不同的数据类型来扩大规模。我相信如果你碰巧需要的话,你可以看看如何将概念扩展到处理任意长度的位数组。

答案 2 :(得分:3)

如果您真的想要最大的内存效率,可以将Huffman树本身编码为比特流。例如,见:

https://www.siggraph.org/education/materials/HyperGraph/video/mpeg/mpegfaq/huffman_tutorial.html

然后只将这些位编码为一个字节数组,可能浪费7位。

但那将是一个可怕的想法。为了使内存中的结构有用,它必须易于访问。你仍然可以非常有效地做到这一点。假设您想要编码最多12位代码。使用16位整数和位域:

struct huffcode {
    uint16_t length: 4,
             value: 12;
}

C将此值存储为单个16位值,并允许您分别访问长度和值字段。完整的Huffman节点还将包含输入代码值和树指针(如果您想要进一步紧凑,则可以是数组中的整数索引)。

答案 3 :(得分:0)

您可以立即制作自己的位数组。

#define ba_set(ptr, bit)   { (ptr)[(bit) >> 3] |= (char)(1 << ((bit) & 7)); }
#define ba_clear(ptr, bit) { (ptr)[(bit) >> 3] &= (char)(~(1 << ((bit) & 7))); }
#define ba_get(ptr, bit)   ( ((ptr)[(bit) >> 3] & (char)(1 << ((bit) & 7)) ?  1 : 0 )
#define ba_setbit(ptr, bit, value) { if (value) { ba_set((ptr), (bit)) } else { ba_clear((ptr), (bit)); } }


#define BITARRAY_BITS  (120)

int main()
{
    char mybits[(BITARRAY_BITS + 7) / 8];
    memset(mybits, 0, sizeof(mybits));

    ba_setbit(mybits, 33, 1);
    if (!ba_get(33))
        return 1;
    return 0;
};