繁体   English   中英

带有bools的C ++ bitfield打包

[英]C++ bitfield packing with bools

我刚刚用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;
};

结果如下: -

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???

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

你的编译器已经在整数大小边界上安排了test3的所有成员。 一旦块被用于给定类型(整数位字段或布尔位字段),编译器就不会分配任何其他类型的位字段,直到下一个边界。

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

编辑:

will be allocated sequentially. c ++编译器将按如下方式在内存中分配位字段:将按顺序分配几个连续位字段成员。 只要需要分配新类型,它就会与下一个逻辑内存块的开头对齐。 下一个逻辑块将取决于您的处理器。 某些处理器可以与8位边界对齐,而其他处理器只能与16位边界对齐。

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

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

小心bitfields,因为它的行为很多是实现(编译器)定义的:

从C ++ 03,9.6 Bitfields(第163页):

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

也就是说,它不是编译器中的错误,而是缺乏它应该如何表现的标准定义。

哇,这太令人惊讶了。 在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;
}

作为一般观察,1位的有符号int并没有多大意义。 当然,你可以弄清楚如何在其中存储0,但麻烦就开始了。

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

对我来说,这种数据类型没有(或者,鉴于史蒂夫的评论, 没什么意义)。

使用unsigned int small : 1; 要使其无符号,那么您可以以非模糊的方式存储值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

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

问题:

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

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

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

“为未命名的位字段指定长度为0具有特殊含义 - 它表示不应将更多的位字段打包到前一位字段的区域中......此处的区域表示一些impl。定义的存储单元”

这是你期望的,还是编译错误?

所以在C89,C89中有修正案I,C99 - 这不是一个错误。 关于C ++我不知道,但我认为行为是类似的。

暂无
暂无

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

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