简体   繁体   English

带有bools的C ++ bitfield打包

[英]C++ bitfield packing with bools

I've just done a test with bitfields, and the results are surprising me. 我刚刚用bitfields做了一个测试,结果令我感到惊讶。

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,顺便说一下......)

your compiler has arranged all of the members of test3 on integer size boundaries. 你的编译器已经在整数大小边界上安排了test3的所有成员。 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. 一旦块被用于给定类型(整数位字段或布尔位字段),编译器就不会分配任何其他类型的位字段,直到下一个边界。

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 type will be allocated sequentially. c ++编译器将按如下方式在内存中分配位字段:将按顺序分配几个相同类型的连续位字段成员。 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. 某些处理器可以与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). 在test3中,每个成员的类型与之前的成员类型不同,因此内存分配将为8 *(系统上的最小逻辑块大小)。 In your case, the minimum block size is two bytes (16-bit), so the size of test3 is 8*2 = 16. 在您的情况下,最小块大小是两个字节(16位),因此test3的大小是8 * 2 = 16。

On a system that can allocate 8-bit blocks, I would expect the size to be 8. 在可以分配8位块的系统上,我希望大小为8。

Be careful with bitfields as much of its behavior is implementation (compiler) defined: 小心bitfields,因为它的行为很多是实现(编译器)定义的:

From C++03, 9.6 Bitfields (pg. 163): 从C ++ 03,9.6 Bitfields(第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. 也就是说,它不是编译器中的错误,而是缺乏它应该如何表现的标准定义。

Wow, that's surprising. 哇,这太令人惊讶了。 In GCC 4.2.4, the results are 1, 4, and 4, respectively, both in C and C++ modes. 在GCC 4.2.4中,结果分别为C和C ++模式的1,4和4。 Here's the test program I used that works in both C99 and C++. 这是我使用的测试程序,它适用于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;
}

As a general observation, a signed int of 1 bit doesn't make a lot of sense. 作为一般观察,1位的有符号int并没有多大意义。 Sure, you can probably figure out how to store 0 in it, but then the trouble starts. 当然,你可以弄清楚如何在其中存储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; 使用unsigned int small : 1; to make it unsigned, then you can store the values 0 and 1 in a non-ambiguous manner. 要使其无符号,那么您可以以非模糊的方式存储值0和1。

#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

From "Samuel P. Harbison, Guy L. Steele] CA Reference": 来自“Samuel P. Harbison,Guy L. Steele] CA Reference”:

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具有特殊含义 - 它表示不应将更多的位字段打包到前一位字段的区域中......此处的区域表示一些impl。定义的存储单元”

Is this what you'd expect, or a compiler bug? 这是你期望的,还是编译错误?

So within C89, C89 with amendment I, C99 - it is not a bug. 所以在C89,C89中有修正案I,C99 - 这不是一个错误。 About C++ I don't know, but I think that the behavior is similar. 关于C ++我不知道,但我认为行为是类似的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM