Неверный размер структуры при использовании битовых полей - PullRequest
2 голосов
/ 29 марта 2019

Недавно мне пришлось иметь дело с битовыми полями в структурах, и я столкнулся с поведением, которое я не могу объяснить.

Следующая структура должна составлять 9 байтов, в соответствии с индивидуальным размером.Но выполнение sizeof основной структуры дает 10 байт.

Следующая программа выдает «10; 1 1 2 1 2 1 1 = 9»

int main(){
    struct{
        uint8_t doubleoscillator;

        struct{
            char monophonic : 1;
            char hold : 1;
            char padding : 6;
        } test;

        int16_t osc1_multisound; //int
        int8_t osc1_octave; // -2..1
        int16_t osc2_multisound; //int
        int8_t osc2_octave; // -2..1
        int8_t intervall;
    }osc;
    std::cout << sizeof(osc) << "; ";

    int a[7];
    a[0] = sizeof(osc.doubleoscillator);
    a[1] = sizeof(osc.test);
    a[2] = sizeof(osc.osc1_multisound);
    a[3] = sizeof(osc.osc1_octave);
    a[4] = sizeof(osc.osc2_multisound);
    a[5] = sizeof(osc.osc2_octave);
    a[6] = sizeof(osc.intervall);

    int total = 0;
    for(int i=0;i<7;i++){
        std::cout << a[i] << " ";
        total += a[i];
    }

    std::cout << " = " << total << std::endl;
    return 0;
}

Почему сумма индивидуального sizeof() внутренних переменных структуры выдает результат, отличный от sizeof () структуры osc?? 1009 *

1 Ответ

2 голосов
/ 29 марта 2019

Прежде всего, из соображений производительности, заполнение добавляется перед каждым элементом структуры, чтобы выровнять указанный элемент в структуре памяти структуры. Таким образом, ocs2_multisound, вероятно, имеет перед ним байт заполнения, чтобы гарантировать, что он появляется в количестве байтов в структуре, кратной 2 (потому что int16_t имеет выравнивание 2).

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

Выравнивание типа можно проверить во время компиляции через alignof(T), где T - это тип.

Увеличение размера в этом случае неизбежно, но общий совет для сокращения байтов заполнения состоит в том, чтобы упорядочивать элементы структуры в порядке нисходящего выравнивания. Это связано с тем, что следующий элемент гарантированно будет правильно выровнен без необходимости дополнения, поскольку предыдущее поле имело либо такое же выравнивание, либо более строгое выравнивание. Поэтому, если будет добавлен какой-либо отступ, он будет дополнять только общий размер структуры, а не (впустую) заполнение между полями.

Причиной выравнивания является прежде всего эффективность в наши дни. Чтение невыровненного блока памяти на оборудовании, которое его поддерживает, обычно примерно вдвое медленнее, потому что он фактически читает два блока памяти вокруг него и извлекает то, что ему нужно. Однако есть также оборудование, которое просто не будет работать, если вы попытаетесь прочитать / записать невыровненную память. Такое оборудование обычно вызывает аппаратное исключение в этом случае.

...