38

我刚刚对位域进行了测试,结果令我惊讶。

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

4

6 回答 6

31

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

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

编辑:

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

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

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

于 2008-11-21T10:40:22.507 回答
20

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

从 C++03,9.6 位域(第 163 页)开始:

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

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

于 2008-11-21T13:23:03.430 回答
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;
}
于 2008-11-21T10:42:39.087 回答
5

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

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

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

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

于 2008-11-21T11:17:19.843 回答
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
于 2010-05-28T13:34:16.660 回答
0

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

问题:

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

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

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

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

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

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

于 2015-02-24T10:42:42.517 回答