带有bools的C++ bitfield打包

Rod*_*ddy 30 c++ bit-fields

我刚刚用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;
};
Run Code Online (Sandbox Code Playgroud)

结果如下: -

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???
Run Code Online (Sandbox Code Playgroud)

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

e.J*_*mes 27

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

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

编辑:

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

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

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


Dav*_*eas 16

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

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

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

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


Chr*_*ung 7

哇,这太令人惊讶了.在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;
}
Run Code Online (Sandbox Code Playgroud)


unw*_*ind 5

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

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

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

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

  • 如果是二进制补码的带符号 1 位值,则清除位表示 0,设置位表示 -1。问题出在哪里?;-) (13认同)