簡體   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