使用 bool 打包 C++ 位域

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/308364/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:31:34  来源:igfitidea点击:

C++ bitfield packing with bools

c++bit-fields

提问by Roddy

I've just done a test with bitfields, and the results are surprising me.

我刚刚用位域做了一个测试,结果让我很惊讶。

class test1 {
public:
    bool test_a:1;
    bool test_b:1;
    bool test_c:1;
    bool test_d:1;
    bool test_e:1;
    bool test_f:1;
    bool test_g:1;
    bool test_h:1;
};

class test2 {
public:
    int test_a:1;
    int test_b:1;
    int test_c:1;
    int test_d:1;
    int test_e:1;
    int test_f:1;
    int test_g:1;
    int test_h:1;
};

class test3 {
public:
    int test_a:1;
    bool test_b:1;
    int test_c:1;
    bool test_d:1;
    int test_e:1;
    bool test_f:1;
    int test_g:1;
    bool test_h:1;
};

The results were:-

结果是:-

sizeof(test1) = 1   // This is what I'd expect. 8 bits in a byte
sizeof(test2) = 4   // Reasonable. Maybe padded out to the size of an int.
sizeof(test3) = 16  // What???

Is this what you'd expect, or a compiler bug? (Codegear C++ Builder 2007, btw...)

这是您所期望的,还是编译器错误?(Codegear C++ Builder 2007,顺便说一句...)

采纳答案by e.James

your compiler has arranged all of the members of test3 on integer size boundaries. Once a block has been used for a given type (integer bit-field, or boolean bit-field), the compiler does not allocate any further bit fields of a different type until the next boundary.

您的编译器已将 test3 的所有成员安排在整数大小边界上。一旦块已用于给定类型(整数位域或布尔位域),编译器在下一个边界之前不会分配任何其他类型的位域。

I doubt it is a bug. It probably has something to do with the underlying architecture of your system.

我怀疑这是一个错误。它可能与您系统的底层架构有关。

edit:

编辑:

c++ compilers will allocate bit-fields in memory as follows: several consecutive bit-field members of the same typewill be allocated sequentially. As soon as a new type needs to be allocated, it will be aligned with the beginning of the next logical memory block. The next logical block will depend on your processor. Some processors can align to 8-bit boundaries, while others can only align to 16-bit boundaries.

c++ 编译器将按如下方式在内存中分配位域:相同类型的多个连续位域成员将按顺序分配。一旦需要分配新类型,它将与下一个逻辑内存块的开头对齐。下一个逻辑块将取决于您的处理器。一些处理器可以对齐到 8 位边界,而其他处理器只能对齐到 16 位边界。

In your test3, each member is of a different type than the one before it, so the memory allocation will be 8 * (the minimum logical block size on your system). In your case, the minimum block size is two bytes (16-bit), so the size of test3 is 8*2 = 16.

在您的 test3 中,每个成员的类型都与之前的不同,因此内存分配将为 8 *(系统上的最小逻辑块大小)。在您的情况下,最小块大小为两个字节(16 位),因此 test3 的大小为 8*2 = 16。

On a system that can allocate 8-bit blocks, I would expect the size to be 8.

在可以分配 8 位块的系统上,我希望大小为 8。

回答by David Rodríguez - dribeas

Be careful with bitfields as much of its behavior is implementation (compiler) defined:

小心位域,因为它的大部分行为是由实现(编译器)定义的:

From C++03, 9.6 Bitfields (pg. 163):

来自 C++03,9.6 位域(第 163 页):

Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit. [Note:bit-fields straddle allocation units on some machines and not on others. Bit-fields are assigned right-to-left on some machines, left-to-right on others. ]

类对象中位域的分配是实现定义的。位域的对齐是实现定义的。位域被打包到一些可寻址的分配单元中。[注意:位域跨越一些机器上的分配单元而不是其他机器。位域在某些机器上从右到左分配,在其他机器上从左到右分配。]

That is, it is not a bug in the compiler but rather lack of a standard definition of how it should behave.

也就是说,它不是编译器中的错误,而是缺乏对其行为方式的标准定义。

回答by Chris Jester-Young

Wow, that's surprising. In GCC 4.2.4, the results are 1, 4, and 4, respectively, both in C and C++ modes. Here's the test program I used that works in both C99 and C++.

哇,这太令人惊讶了。在 GCC 4.2.4 中,C 和 C++ 模式下的结果分别为 1、4 和 4。这是我使用的测试程序,它适用于 C99 和 C++。

#ifndef __cplusplus
#include <stdbool.h>
#endif
#include <stdio.h>

struct test1 {
    bool test_a:1;
    bool test_b:1;
    bool test_c:1;
    bool test_d:1;
    bool test_e:1;
    bool test_f:1;
    bool test_g:1;
    bool test_h:1;
};

struct test2 {
    int test_a:1;
    int test_b:1;
    int test_c:1;
    int test_d:1;
    int test_e:1;
    int test_f:1;
    int test_g:1;
    int test_h:1;
};

struct test3 {
    int test_a:1;
    bool test_b:1;
    int test_c:1;
    bool test_d:1;
    int test_e:1;
    bool test_f:1;
    int test_g:1;
    bool test_h:1;
};

int
main()
{
    printf("%zu %zu %zu\n", sizeof (struct test1), sizeof (struct test2),
                            sizeof (struct test3));
    return 0;
}

回答by unwind

As a general observation, a signed intof 1 bit doesn't make a lot of sense. Sure, you can probably figure out how to store 0 in it, but then the trouble starts.

作为一般观察,int1 位有符号意义不大。当然,您可能会想出如何在其中存储 0,但随后麻烦就来了。

One bit must be the sign-bit, even in two's complement, but you only have one bit to play with. So, if you allocate that as the sign-bit, you have no bits left for the actual value. It's true as Steve Jessop points out in a comment that you could probably represent -1 if using two's complement, but I still think that an "integer" datatype that can only represent 0 and -1 is a rather weird thing.

一位必须是符号位,即使在二进制补码中,但您只有一位可以玩。因此,如果您将其分配为符号位,则实际值没有剩余位。正如 Steve Jessop 在评论中指出的那样,如果使用二进制补码,您可能可以表示 -1,但我仍然认为只能表示 0 和 -1 的“整数”数据类型是一件相当奇怪的事情。

To me, this datatypes makes no (or, given Steve's comment, little) sense.

对我来说,这种数据类型没有(或者,根据史蒂夫的评论,几乎没有)意义。

Use unsigned int small : 1;to make it unsigned, then you can store the values 0 and 1 in a non-ambiguous manner.

使用unsigned int small : 1;使其无符号,然后您可以以明确的方式存储值 0 和 1。

回答by t1t0

#include <iostream>
using namespace std;

bool ary_bool4[10];

struct MyStruct {
    bool a1 :1;
    bool a2 :1;
    bool a3 :1;
    bool a4 :1;
    char b1 :2;
    char b2 :2;
    char b3 :2;
    char b4 :6;
    char c1;
};

int main() {
    cout << "char size:\t" << sizeof(char) << endl;
    cout << "short int size:\t" << sizeof(short int) << endl;
    cout << "default int size:\t" << sizeof(int) << endl;
    cout << "long int size:\t" << sizeof(long int) << endl;
    cout << "long long int size:\t" << sizeof(long long int) << endl;
    cout << "ary_bool4 size:\t" << sizeof(ary_bool4) << endl;
    cout << "MyStruct size:\t" << sizeof(MyStruct) << endl;
    // cout << "long long long int size:\t" << sizeof(long long long int) << endl;
    return 0;
}

char size: 1
short int size: 2
default int size: 4
long int size: 4
long long int size: 8
ary_bool4 size: 10
MyStruct size: 3

回答by bruziuz

From "Samuel P. Harbison, Guy L. Steele] C A Reference":

来自“Samuel P. Harbison, Guy L. Steele] CA 参考”:

The problem:

问题:

"Compilers are free to impose constraints on the maximum size of a bit field, and specify certain addressing boundaries that bit field cannot cross."

“编译器可以自由地对位域的最大大小施加限制,并指定位域不能跨越的某些寻址边界。”

Manipulations which can be done within standard:

可以在标准范围内完成的操作:

"An unnamed bit field may also be included in a structure to provide padding."

“一个未命名的位字段也可以包含在一个结构中以提供填充。”

"Specify a length of 0 for unnamed bit field has a special meaning - it indicates that no more bit fields should be packed into the area in which the previous bit field...Area here means some impl. defined storage unit"

“为未命名位字段指定长度为 0 具有特殊含义 - 它表示不应再将位字段打包到前一个位字段所在的区域中......这里的区域意味着一些隐含定义的存储单元”

Is this what you'd expect, or a compiler bug?

这是您所期望的,还是编译器错误?

So within C89, C89 with amendment I, C99 - it is not a bug. About C++ I don't know, but I think that the behavior is similar.

因此,在 C89、C89 和修正 I、C99 中 - 这不是错误。关于 C++ 我不知道,但我认为行为是相似的。