我注意到C中的单个位没有内置结构。有(无符号)char和int,它们是8位(一个字节),long是64+位,所以on(uint64_t,bool ...)
我在编写一个霍夫曼树时遇到了这个问题,并且某些字符的编码不一定是8位长(如00101),因此没有有效的方法来存储编码。我必须找到临时解决方案,如字符串或布尔数组,但这需要更多的内存。
但无论如何,我的问题更为笼统:是否有一种存储位的数组或某种用户定义结构的好方法?我在网上搜索了一个,但最小的结构似乎是8位(一个字节)。我尝试了诸如int a : 1
之类的东西,但它没有用。我读到了有关字段的内容,但它们并不能简单地实现我想做的事情。我知道在C ++中已经有人问过这个问题,如果有一个结构用于单个位,但大多数情况下我想知道什么是在C中存储编码如00101的最节省内存的方法。
答案 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;
};