我正在尝试存储在运行时确定的大量布尔信息。我想知道最好的方法是什么。
我目前一直在尝试使用以下方式分配内存:
pStatus = malloc((<number of data points>/8) + 1);
认为这会给我足够的工作量。然后,我可以使用数组表示法中的指针引用每个布尔值:
pStatus[element]
不幸的是,这似乎并没有很好地发挥作用。首先,我很难将内存初始化为整数值0
。可以使用memset()
完成吗?尽管如此,我认为这不会影响我在尝试访问pStatus[element]
时崩溃的原因。
我也不完全相信这种方法是最好的方法。我真正想要的本质上是一个反映布尔值状态的巨型位掩码。我错过了什么吗?
答案 0 :(得分:29)
pStatus = malloc((<number of data points>/8) + 1);
这确实为您的位分配了足够的字节。然而,
pStatus[element]
它访问元素'字节,而不是位。因此,当元素超过总位数的八分之一时,您将访问所分配数组的末尾。
我会定义一些辅助函数
int get_bit(int element)
{
uint byte_index = element/8;
uint bit_index = element % 8;
uint bit_mask = ( 1 << bit_index);
return ((pStatus[byte_index] & bit_mask) != 0);
}
void set_bit (int element)
{
uint byte_index = element/8;
uint bit_index = element % 8;
uint bit_mask = ( 1 << bit_index);
pStatus[byte_index] |= bit_mask);
}
void clear_bit (int element)
{
uint byte_index = element/8;
uint bit_index = element % 8;
uint bit_mask = ( 1 << bit_index);
pStatus[byte_index] &= ~bit_mask;
}
(为了清楚起见,错误检查了元素的范围。你也可以制作这个宏)
答案 1 :(得分:7)
...认为这会给我足够的工作量。然后,我可以使用数组表示法中的指针引用每个布尔值:
pStatus[element]
元素是寻址字节,而不是位。你想要这样的东西:
pStatus[element/8] & (1 << (element % 8))
答案 2 :(得分:5)
小点:要获得足够的内存来存储N位,(N / 8)+ 1个字节是不精确的(可能是太多)。
(N + 7)/ 8总是最小数字。
答案 3 :(得分:4)
嗯,最简单的答案是使用calloc而不是malloc。
它被定义为初始化它分配给零的内存,并且通常可以通过使用页面映射技巧来实现。
这会照顾你的内存初始化问题。这里的其他几十个帖子似乎足以解决索引问题以及你偶尔会分配一个额外字节的事实(哦恐怖!),所以我不会在这里重复他们的内容。
答案 4 :(得分:2)
pStatus [element]将在该地址给你一个完整的字节。
要设置特定元素,您可以执行以下操作:
pStatus[element >> 3] |= 1 << (element & 7);
要重置元素:
pStatus[element >> 3] &= ~1 << (element & 7);
并测试元素:
if (pStatus[element >> 3] & (1 << (element & 7)) != 0)
初始分配应为
pstatus = malloc((<number of data points> + 7) / 8)
你的工作会偶尔浪费一个字节
答案 5 :(得分:2)
我不禁注意到,C中的所有回复似乎都假设一个字节是8位。这在C中并不一定正确(尽管在大多数主流硬件上都是如此),因此在代码中进行这种假设是相当糟糕的形式。
编写体系结构中立代码的正确方法是
#include <limits.h>
然后在需要的地方使用CHAR_BIT
宏“char
”中的位数。
答案 6 :(得分:1)
让自己更快乐,并定义一种类型和功能来操作该类型。这样,如果您发现位访问太慢,您可以将每布尔的内存单位更改为字节/字/长,或者如果内存确实存在问题则采用稀疏/动态数据结构(即,如果您的集合大多为零) ,你可以保留一个包含1的坐标的列表。
您可以编写代码,使其完全不受位向量实现更改的影响。
答案 7 :(得分:0)
pStatus [element]没有解决这个问题。它得到的确切字节取决于pStatus的类型 - 我假设是char *或等价的 - 所以pStatus [element]会得到元素的第一个字节。
你可以将memset设置为0,是的。
答案 8 :(得分:0)
pStatus = malloc((<number of data points>/8) + 1);
那部分没事。
pStatus[element]
这是你遇到麻烦的地方。当你想要寻址位时,你是地址字节。
pStatus[element / 8 ]
会在数组中找到正确的字节。
答案 9 :(得分:0)
您需要分配c = malloc((N+7)/8)
个字节,并且可以使用
c[n/8]=((c[n/8] & ~(0x80 >> (n%8))) | (0x80>>(n%8)));
清楚
c[n/8] &= ~(0x80 >> (n%8));
并使用
进行测试 if(c[n/8] & (0x80 >> (n%8))) blah();
答案 10 :(得分:0)
如果您不介意必须编写包装器,您也可以使用C ++的STL中的bit_set或bit_vector,看起来它们(特别是后者)正是您需要的,已经编码,测试和打包(并且有很多)钟声和口哨)。
真的很遗憾我们缺乏在C应用程序中使用C ++代码的直接方式(不,创建包装器对我来说不是直截了当,也不是很有趣,并且意味着长期工作更多)。
答案 11 :(得分:0)
std::vector<bool>
会出现什么问题?
答案 12 :(得分:0)
让我感到惊讶的是,这里只有一个答案提到了CHAR_BIT。一个字节通常是8位,但并非总是如此。
答案 13 :(得分:-1)
您的分配代码是正确的,请参阅this answer中给出的set_bit()
和get_bit()
函数以访问布尔值。
答案 14 :(得分:-1)
布尔值是“从不”C中的单独值。所以结构可能是为了让你前进。
您确实没有初始化mem区域,因此您需要单独执行此操作。
这是一个简单的例子,说明如何使用联合结构和枚举
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long int DWORD;
typedef unsigned long long int DDWORD;
enum STATUS
{
status0 = 0x01,
status1 = 0x02,
status2 = 0x04,
status3 = 0x08,
status4 = 0x10,
status5 = 0x20,
status6 = 0x40,
status7 = 0x80,
status_group = status0 + status1 +status4
};
#define GET_STATUS( S ) ( ((status.DDBuf&(DDWORD)S)==(DDWORD)S) ? 1 : 0 )
#define SET_STATUS( S ) ( (status.DDBuf|= (DDWORD)S) )
#define CLR_STATUS( S ) ( (status.DDBuf&= ~(DDWORD)S) )
static union {
BYTE BBuf[8];
WORD WWBuf[4];
DWORD DWBuf[2];
DDWORD DDBuf;
}status;
int main(void)
{
// Reset status bits
status.BBuf[0] = 0;
printf( "%d \n", GET_STATUS( status0 ) );
SET_STATUS( status0 );
printf( "%d \n", GET_STATUS( status0 ) );
CLR_STATUS(status0);
printf( "%d \n", GET_STATUS( status0 ) );
SET_STATUS( status_group );
printf( "%d \n", GET_STATUS( status0 ) );
system( "pause" );
return 0;
}
希望这会有所帮助。此示例可以处理64个状态布尔值,并且可以轻松扩展。
此exapmle基于Char = 8位int = 16位long int = 32位且long long int = 64位
我现在还添加了对状态组的支持。
答案 15 :(得分:-1)
如果你只限于几位你可以代替eaanon01解决方案也可以使用bitfield的c内置工具(很少有你可以使用它们的场合,但这将是一个)
对于这个比特敲打的东西我可以推荐: Herny Warrens“Hacker Delight”