Intereting Posts
Как отсортировать стек, используя только Push, Pop, Top, IsEmpty, IsFull? Использование указателя на динамический 2D-массив внутри структуры Почему float при преобразовании в int округляется ниже в C? вернуть несколько значений из функции в C Есть ли способ заставить мою программу работать с меньшим количеством кода? Обработка ошибок scanf C Печать нескольких целых чисел как одна произвольно длинная десятичная строка Преобразовать float в unsigned long для доступа к внутренним элементам float, в c #define Почему нужно указывать указатель на массив перед передачей в качестве параметра функции с аргументом типа массива? Как я могу напечатать результат sizeof () во время компиляции в C? Делает ли iterator курсором ускорение цикла C? Ошибка связи в Java Введите символ в качестве ввода целочисленной переменной, предоставив бесконечный цикл Смешивание объявлений с внешним, статическим и отсутствующим спецификатором хранилища в глобальной области видимости Чтение в строке с пробелами в C

Почему в структуре нет прописных элементов только для членов типа «char»?

Я объявил в структуре только члены типа char .

 #include  struct st { char c1; char c2; char c3; char c4; char c5; }; int main() { struct st s; printf("%zu\n", sizeof(s)); return 0; } 

Выход: [ Live Demo ]

 5 

Итак, почему в структуре нет char элементов только для членов типа char ?

Прокладка в структуре существует (в основном) для обеспечения того, чтобы отдельные члены были привязаны к их основному требованию выравнивания , то есть ( C11 3.2p1 ):

требование о том, чтобы объекты определенного типа располагались на границах хранилища с адресами, которые являются частями кратного байтового адреса

Прокладка в середине и в конце структуры используется для обеспечения того, что даже в пределах массива этих структур каждый элемент будет по-прежнему выровнен в соответствии с их требованиями к выравниванию. C11 6.2.8p1 :

Полные типы объектов имеют требования к выравниванию, которые ограничивают адреса, по которым могут быть выделены объекты этого типа. Выравнивание представляет собой целочисленное значение, определяемое реализацией, представляющее количество байтов между последовательными адресами, по которым может быть выделен данный объект. Тип объекта налагает требование выравнивания для каждого объекта такого типа: более строгое выравнивание можно запросить с помощью ключевого слова _Alignas.

Теперь требование выравнивания для каждого другого типа определяется реализацией, но подразумевается одно: поскольку требование выравнивания выражается в size_t ; sizeof (char) равен 1, а указатели на типы символов могут использоваться для адресации каждого отдельного символа в других типах, тип символа не может иметь фундаментальное требование выравнивания больше 1. Неожиданно это не указано в стандарте C вообще ; у этого просто есть эта неопределенная формулировка ( C11 6.2.8p6 ):

Типы char , signed char и unsigned char должны иметь самое слабое требование к выравниванию.

Поскольку выравнивание char не более 1, компилятору не нужно добавлять никаких дополнений, потому что даже если структура имеет ровно 5 байтов, то даже в массиве с некоторыми структурами, начинающимися с нечетного адреса, каждый из элементов этих структур все равно будут правильно выровнены.

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


В вашем примере нет необходимости заполнить, так как все члены st структуры уже выровнены по своему размеру, то есть: адрес каждого элемента st уже делится на его размер. Все члены имеют тип char и размер char равен 1 . Если размер участника равен 1 , этот член всегда выровнен по своему размеру, так как любой адрес делится на 1 .

Некоторые типы, когда они правильно выровнены, имеют лучшую производительность / стабильность и т. Д. Если для переменной такого типа есть другие переменные, которые делают его исходное положение «не выровненным», компилятор может принять решение добавить дополнение, чтобы выравнивание проходило хорошо , Это все необязательно, и, конечно, нет необходимости, когда у вас есть байты ( char ).

Скорее всего, вы заметите прописку, если вы создадите такую ​​структуру:

 struct pad{ int8_t a; int64_t b; }; assert(sizeof(struct pad) == 16); 

чей формат памяти должен выглядеть так:

 |---|-------|---------| | 1 | 7 | 8 | |---|-------|---------| byte|padding|64-bit int 

Опять же, нет необходимости выровнять байты, поскольку они являются минимальной единицей хранения.