我可以在 C 中分配特定数量的位数吗?

发布于 2024-07-08 23:24:36 字数 431 浏览 11 评论 0原文

我试图存储在运行时确定的大量布尔信息。 我想知道最好的方法是什么。

我目前一直在尝试使用以下方式分配内存:

pStatus = malloc((<数据点数量>/8) + 1);

认为这将为我提供足够的位来使用。 然后,我可以使用数组表示法中的指针引用每个布尔值:

pStatus[element]

不幸的是,这似乎工作得不太好。 首先,我很难将内存初始化为整数值0。 可以使用 memset() 来完成吗? 不过,我认为这不会影响我在尝试访问 pStatus[element] 时崩溃的原因。

我也不完全相信这种方法是最好的方法。 我真正想要的是一个反映布尔值状态的巨大位掩码。 我错过了什么吗?

I am trying to store a large amount of boolean information that is determined at run-time. I was wondering what the best method might be.

I have currently been trying to allocate the memory using:

pStatus = malloc((<number of data points>/8) + 1);

thinking that this will give me enough bits to work with. I could then reference each boolean value using the pointer in array notation:

pStatus[element]

Unfortunately this does not seem to be working very well. First, I am having difficulty initializing the memory to the integer value 0. Can this be done using memset()? Still, I don't think that is impacting why I crash when trying to access pStatus[element].

I am also not entirely convinced that this approach is the best one to be using. What I really want is essentially a giant bitmask that reflects the status of the boolean values. Have I missed something?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

指尖上得阳光 2024-07-15 23:24:36
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;
}

(为了清楚起见,对元素范围进行错误检查。您也可以制作这个宏)

pStatus = malloc((<number of data points>/8) + 1);

This does allocate enough bytes for your bits. However,

pStatus[element]

This accesses the element'th byte, not bit. So when element is more than one-eighth of the total number of bits, you're accessing off the end of the array allocated.

I would define a few helper functions

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

(error checking on range of element left out for clarity. You could make this macros, too)

ぺ禁宫浮华殁 2024-07-15 23:24:36

...认为这会给我足够的空间来工作。 然后,我可以使用数组表示法中的指针引用每个布尔值:

pStatus[element]

元素寻址字节,而不是位。 你想要类似的东西:

pStatus[element/8] & (1 << (element % 8))

...thinking that this will give me enough bits to work with. I could then reference each boolean value using the pointer in array notation:

pStatus[element]

element is addressing bytes, not bits. You want something like:

pStatus[element/8] & (1 << (element % 8))
ゃ懵逼小萝莉 2024-07-15 23:24:36

小一点:要获得足够的内存来存储 N 位,(N/8) + 1 字节是不精确的(可能是太多)。

不过,(N+7)/8 始终是最小数。

Small point: to get enough memory to store N bits, (N/8) + 1 bytes is imprecise (can be one too many).

(N+7)/8 is always the minimum number, though.

甜扑 2024-07-15 23:24:36

嗯,最简单的答案是使用 calloc 而不是 malloc。

它被定义为将其分配的内存初始化为零,并且通常可以通过使用页面映射技巧来实现。

这将解决您的内存初始化问题。 这里的其他十几篇文章似乎充分解决了索引问题以及您偶尔分配额外字节的事实(哦,太恐怖了!),所以我不会在这里重复他们的内容。

Well, the simplest answer would be to use calloc instead of malloc.

It is defined to initialize the memory it allocates to zero, and can often do it by using page mapping tricks.

That will take care of your memory initialization problem. The other dozen posts here seem to adequately address the indexing problem and the fact that you occasionally allocate an extra byte (oh the horror!), so I won't repeat their content here.

八巷 2024-07-15 23:24:36

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)

您可以工作但偶尔会浪费一个字节的内容

pStatus[element] will give you an entire byte at that address.

To set a particular element you would do something like:

pStatus[element >> 3] |= 1 << (element & 7);

To reset an element:

pStatus[element >> 3] &= ~1 << (element & 7);

and to test an element:

if (pStatus[element >> 3] & (1 << (element & 7)) != 0)

the initial allocation should be

pstatus = malloc((<number of data points> + 7) / 8)

what you had will work but wastes a byte occasionally

静赏你的温柔 2024-07-15 23:24:36

我不禁注意到,这里所有的 C 回复似乎都假设一个字节是 8 位。 这在 C 语言中不一定是正确的(尽管在大多数主流硬件上当然是正确的),因此在代码中做出这种假设是相当糟糕的形式。

编写与体系结构无关的代码的正确方法是,

#include <limits.h>

然后在需要“char 中的位数”的地方使用 CHAR_BIT 宏。

I can't help but notice that all replies in C here seem to assume that a byte is 8 bits. This is not necessarily true in C (although it will of course be true on most mainstream hardware), so making this assumption in code is rather bad form.

The proper way to write architecture-neutral code is to

#include <limits.h>

and then use the CHAR_BIT macro wherever you need "the number of bits in a char".

于我来说 2024-07-15 23:24:36

让自己更快乐并定义一个类型和对该类型进行操作的函数。 这样,如果您发现位访问太慢,则可以将每个布尔值的内存单位更改为字节/字/长,或者如果内存确实是一个问题(即,如果您的集合大部分为零),则采用稀疏/动态数据结构,您可以只保留一个包含 1 坐标的列表。

您可以编写代码以完全不受位向量实现的更改的影响。

Make yourself happier and define a type and functions to operate on that type. That way if you discover that bit accesses are too slow, you can change the unit of memory per boolean to a byte/word/long or adopt sparse/dynamic data structures if memory is really an issue (ie, if your sets are mostly zeros, you could just keep a list with the coordinates of the 1's.

You can write your code to be completely immune to changes to the implementation of your bit vector.

旧时浪漫 2024-07-15 23:24:36

pStatus[element] 不寻址该位。 它获得的确切字节取决于 pStatus 的类型 - 我假设 char* 或等效的 - 所以 pStatus[element] 为您提供第一个元素的字节。

你可以 memset 设置为 0,是的。

pStatus[element] does not address the bit. The exact byte it gets is dependent on the type of pStatus -- I assume char* or equivalent -- so pStatus[element] gets you the element'th byte.

You could memset to set to 0, yes.

把人绕傻吧 2024-07-15 23:24:36
 pStatus = malloc((<number of data points>/8) + 1);

那部分很好。

 pStatus[element]

这就是你遇到麻烦的地方。 当你想要寻址位时,你就是寻址字节。

 pStatus[element / 8 ]  

将为您提供数组中正确的字节。

 pStatus = malloc((<number of data points>/8) + 1);

That part's fine.

 pStatus[element]

here's where you have trouble. You are address bytes, when you want to address bits.

 pStatus[element / 8 ]  

will get you the right byte in the array.

一刻暧昧 2024-07-15 23:24:36

您需要分配c = malloc((N+7)/8)字节,并且您可以使用

 c[n/8]=((c[n/8] & ~(0x80 >> (n%8))) | (0x80>>(n%8)));

clear with

 c[n/8] &= ~(0x80 >> (n%8));

设置第n个并使用test with

 if(c[n/8] & (0x80 >> (n%8))) blah();

You need to allocate c = malloc((N+7)/8) bytes, and you can set the nth with

 c[n/8]=((c[n/8] & ~(0x80 >> (n%8))) | (0x80>>(n%8)));

clear with

 c[n/8] &= ~(0x80 >> (n%8));

and test with

 if(c[n/8] & (0x80 >> (n%8))) blah();
看海 2024-07-15 23:24:36

如果你不介意必须编写包装器,你也可以使用 C++ 的 STL 中的 bit_set 或 bit_vector,看起来它们(尤其是后者)正是你所需要的,已经编码、测试和打包(以及大量的附加功能) )。

令人遗憾的是,我们缺乏在 C 应用程序中使用 C++ 代码的直接方法(不,创建包装器对我来说并不直接,也不有趣,而且从长远来看意味着需要更多工作)。

If you don't mind having to write wrappers, you could also use either bit_set or bit_vector from C++'s STL, seems like they (especially the latter) have exactly what you need, already coded, tested and packaged (and plenty of bells and whistles).

It's a real shame we lack a straight forward way to use C++ code in C applications (no, creating a wrapper isn't straight-forward to me, nor fun, and means more work in the long term).

故乡的云 2024-07-15 23:24:36

std::vector 会出现什么问题?

What would be wrong with std::vector<bool>?

我要还你自由 2024-07-15 23:24:36

令我惊讶的是,这里只有一个答案提到了 CHAR_BIT。 一个字节通常是 8 位,但也不总是如此。

It amazes me that only one answer here mentions CHAR_BIT. A byte is often 8 bits, but not always.

儭儭莪哋寶赑 2024-07-15 23:24:36

您的分配代码是正确的,请参阅 这个答案来访问布尔值。

You allocation code is correct, see the set_bit() and get_bit() functions given in this answer to access the boolean.

雪化雨蝶 2024-07-15 23:24:36

如果您仅限于几个位,您可以代替 eaanon01 解决方案,还使用 ​​bitfield 的 C 内置工具(很少有场合可以使用它们,但这就是一个)

对于这个位爆炸的东西,我可以推荐:
赫尼·沃伦斯《黑客之乐》

If you are limited to just a few bits you can instead of eaanon01 solution also use the c builtin facility of bitfield (there are very few occasion where you could use them, but this would be one)

For this bit banging stuff I can recommendate:
Herny Warrens "Hacker Delight"

谈情不如逗狗 2024-07-15 23:24:36

在 C 语言中,布尔值“从来”不是一个单独的值。因此,结构体可能是为了让您继续下去。

确实,您没有初始化内存区域,因此您需要单独执行此操作。

这是一个简单的示例,说明如何使用联合结构和枚举来做到这一点

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 个状态布尔值,并且可以轻松扩展。

此示例基于 Char = 8 位 int = 16 位 long int = 32 位和 long long int = 64 位

我现在还添加了对状态组的支持。

The boolean is "never" a separate value in C. So a struct might be in order to get you going.

It is true that you do not initialize the mem area so you need to do that individually.

Here is a simple example of how you could do it with unions structs and enums

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

Hope this helps. This example can handle up until 64 status booleans and could be easy extended.

This exapmle is based on Char = 8 bits int = 16 bits long int = 32 bits and long long int = 64 bits

I have now also added support for status groups.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文