Подтвердить что ты не робот

С++ битпольная упаковка с bools

Я только что прошел тест с битовыми полями, и результаты меня удивляют.

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 С++ Builder 2007, btw...)

4b9b3361

Ответ 1

ваш компилятор упорядочил все члены test3 на границах целочисленного размера. Как только блок используется для заданного типа (целочисленное битовое поле или логическое битовое поле), компилятор не выделяет никаких дополнительных полей бит другого типа до следующей границы.

Я сомневаюсь, что это ошибка. Вероятно, это имеет какое-то отношение к базовой архитектуре вашей системы.

редактировать:

Компиляторы

С++ будут распределять бит-поля в памяти следующим образом: последовательно выделяются несколько последовательных элементов битового поля того же типа. Как только новый тип должен быть выделен, он будет выровнен с началом следующего блока логической памяти. Следующий логический блок будет зависеть от вашего процессора. Некоторые процессоры могут согласовываться с 8-битными границами, в то время как другие могут согласовывать только с 16-разрядными границами.

В вашем test3 каждый элемент имеет другой тип, чем тот, который был перед ним, поэтому распределение памяти будет 8 * (минимальный размер логического блока в вашей системе). В вашем случае минимальный размер блока составляет два байта (16 бит), поэтому размер test3 равен 8 * 2 = 16.

В системе, которая может выделять 8-битные блоки, я бы ожидал, что размер будет равен 8.

Ответ 2

Будьте осторожны с битовыми полями, поскольку большая часть его поведения определяется реализацией (компилятором):

Из С++ 03, 9.6 Бит-биты (стр. 163):

Распределение бит-полей в пределах объект класса реализации. Выравнивание битовые поля определяются реализацией. Бит-поля упаковываются в некоторые адресная единица распределения. [Примечание: распределение полей бит-полей единиц на некоторых машинах, а не на другие. Битовые поля назначаются справа налево на некоторых машинах, слева направо на других. ]

То есть, это не ошибка в компиляторе, а отсутствие стандартного определения того, как он должен себя вести.

Ответ 3

Ничего себе, это удивительно. В GCC 4.2.4 результаты 1, 4 и 4 соответственно, как в режимах C, так и в С++. Здесь тестовая программа, которую я использовал, работает как на C99, так и на С++.

#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;
}

Ответ 4

Как общее замечание, подписанный int 1 бит не имеет большого смысла. Конечно, вы, вероятно, можете выяснить, как хранить 0 в нем, но затем начинается проблема.

Один бит должен быть знаковым битом, даже в двух дополнениях, но у вас есть только один бит для игры. Таким образом, если вы выделите это как знаковый бит, у вас нет битов, оставшихся для фактического значения. Это правда, поскольку Стив Джессоп указывает в комментарии, что вы, вероятно, можете представить -1, если используете два дополнения, но я все же считаю, что "целочисленный" тип данных, который может представлять только 0 и -1, является довольно странным.

Для меня эти типы данных не дают (или, учитывая мнение Стива, мало).

Используйте unsigned int small : 1;, чтобы сделать его неподписанным, тогда вы можете хранить значения 0 и 1 несимметричным образом.

Ответ 5

Нет, это то, чего я ожидал бы, так как порядок значителен. Если вы сгруппировали bools и ints, вы получите совсем другой результат. Как я помню, битполы работают только с общим типом.

Ответ 6

#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

Ответ 7

От "Сэмюэл П. Харбисон, Гай Л. Стил" C Ссылка:

Проблема:

"Компиляторы могут налагать ограничения на максимальный размер битового поля и задавать определенные границы адресации, которые бит не может пересекать."

Манипуляции, которые могут выполняться по стандарту:

"Небезовое битовое поле также может быть включено в структуру для обеспечения заполнения".

"Указать длину 0 для неназванного битового поля имеет особое значение - это указывает на то, что в область, в которой находится предыдущее поле бит, не должно быть больше полей бит... Область здесь означает определенный блок хранения данных"

Это то, что вы ожидаете, или ошибка компилятора?

Итак, в C89, C89 с поправкой I, C99 - это не ошибка. О С++ я не знаю, но я думаю, что поведение похоже.