Системы требуют, чтобы определенные примитивы были выровнены по определенным точкам в памяти (целые числа - байты, кратные 4, короткие - байты, кратные 2, и т. д.). Конечно, их можно оптимизировать, чтобы тратить меньше места на прокладку.
У меня вопрос: почему GCC не делает это автоматически? Отсутствует ли каким-то образом более очевидная эвристика (переменные порядка от требований к самому большому размеру до наименьшего)? Зависит ли какой-то код от физического порядка его структур (это хорошая идея)?
Я спрашиваю только потому, что GCC супер оптимизирован во многих отношениях, но не в этом, и я думаю, что должно быть какое-то относительно крутое объяснение (на которое я не обращаю внимания).





Структуры часто используются в качестве представления порядка упаковки форматов двоичных файлов и сетевых протоколов. Это сломалось бы, если бы это было сделано. Кроме того, разные компиляторы по-разному оптимизируют вещи, и связать код обоих будет невозможно. Это просто невозможно.
это не имеет ничего общего с сетью или файловыми структурами. Действительно, заголовок структуры BMP плотно упакован элементами, попадающими на неестественные границы, чуждые компилятору.
Эээ, да? Вы неправильно истолковали вопрос. Перечитайте второй абзац, где он говорит о упорядочивании структур. Это полностью отличается от заполнения.
ваш первый пункт очень верен. но я думаю, что твой второй - нет. скомпилированный код из разных компиляторов все равно несовместим.
@ JohannesSchaub-litb, что зависит; если оба компилятора придерживаются одного и того же ABI, у них нет причин создавать несовместимый код. Примерами являются GCC и Clang, а также 32-разрядные GCC и MSVC для C в Windows.
Компиляторы C не упаковывают автоматически структуры именно потому, что проблем выравнивания, как вы упомянули. Доступы не на границах слов (32-битные на большинстве процессоров) влекут за собой тяжелые потери на x86 и вызывают фатальные ловушки на архитектурах RISC.
Я не говорил об избавлении от буферизации, я говорю о том, чтобы поставить все длинные / указатели сквозными, затем все короткие, затем все символы сквозными и т. д. так что вы теряете только место в конце.
Что ж, это наполовину правда. Компилятор C по умолчанию упаковывает их, он просто делает это в соответствии с естественными границами слов архитектуры. Вот почему вам нужно #pragma pack (0) структур, которые используют символы / шорты в упакованных протоколах, чтобы они не добавляли отступы.
@Alex, эээ. Вы потратите такое же количество места, так как ваш персонаж должен быть заполнен таким же количеством. Вы не выиграете вообще ни по пространству, ни по производительности.
Ой. Да, это вызывает проблемы с двоичными форматами, как засвидетельствовал Коди. Кроме того, ANSI гарантирует, что смещения элементов структуры должны быть в возрастающем порядке.
@Cody, все пространство будет потрачено впустую в самом конце и меньше или равно обычному случаю и пункту «выделять по мере приближения»: struct blah {char a; короткий б; char c; }; struct blah2 {короткий b; char a, c; }; blah тратит на 2 байта больше, чем blah2
потому что один персонаж может переходить между другим персонажем и коротким, вместо того, чтобы тратить лишний символ для каждого.
Однако это не так. Если вы отключите заполнение, вы получите тот же размер, но потеряете причину, по которой заполнение необходимость - большинство архитектур вообще не могут получить к нему доступ, а те, которые могут, будут делать это медленнее. Итак, вы теряете заполнение и переупорядочиваете, чтобы получить ... то же самое.
вы не потеряете ни одного преимущества заполнения, если правильно упорядочите структуру. С коротким, char, char у вас может быть 0 отступов, но все элементы попадают на правильное смещение. В общем, для этого вы не потеряете никакой скорости, так как падают на свои естественные границы.
Нет, это неверно для большинства архитектур. Даже если это разрешено, доступ к памяти, которая не выровнена по словам (обычно 32-битная), наказывается, даже если это разрешено.
Вы можете поддерживать память с выравниванием слов. Символы могут быть помещены в любой байт (очевидно). Замыкание может быть начато с любого байта, кратного 2. Интервалы с любого байта, кратного 4, заданные char a, b; короткий c; | a | b | c | c допустимо, но преобразованное в a, c, b оно должно быть | a | x | c | c | b | x |
GCC умнее большинства из нас в создании машинного кода из исходного кода; однако я дрожу, если бы он был умнее, чем мы, перестраивая наши структуры, поскольку это данные, которые, например, можно записать в файл. Структура, которая начинается с 4-х символов, а затем имеет 4-байтовое целое число, будет бесполезна при чтении в другой системе, где GCC решил, что он должен переупорядочить элементы структуры.
Чтение / запись структур непосредственно в файл в любом случае не переносится на компилятор / платформу из-за выравнивания (которое разрешено), см. Ответ это SO.
gcc не меняет порядок элементов структуры, потому что это нарушит стандарт C. В разделе 6.7.2.1 стандарта C99 говорится:
Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared.
Да, но почему это было определено именно так?
@ nes1983 Программист может делать предположения относительно порядка данных в структуре и может использовать маскирование для получения каждой части. Если структура переупорядочена, то маскировка будет неправильной.
@ Evo510: Я запуталась. Чтобы использовать маскирование, вы также должны знать отступы, которые не гарантируются языком. Значит, нельзя использовать маски. Я что-то упускаю?
@ nes1983 Я видел код численного интегрирования, который предполагает, что все его входные данные являются числами с плавающей запятой в последовательном порядке. Вы передаете ему указатель на первое значение, которое нужно интегрировать, и последнее, и он просматривает их. Однако вы храните информацию в структуре, потому что для всего, кроме интеграции, это более удобный формат.
Хотя это нарушает стандарт, существует полезный метод переупорядочения для защиты ядра Linux от руткитов / эксплойтов: часть Linux KSPP (kernsec.org/wiki/index.php/Kernel_Self_Protection_Project) - это рандомизация / переупорядочение некоторых структурных полей: openwall.com/lists/kernel-haroding/2017/05/26/8 (введение плагина рандомизации структуры структуры), связанная статья: sec.taylor.edu/doc/… ( «Повышение безопасности ядра за счет рандомизации структуры памяти» - Д.М. Стэнли - 2013 г.)
@ nes1983 Бывают случаи, когда делаются предположения, например, при работе с сетью: вызов connect () указывает sockaddr в качестве аргумента, который в терминах ООП является чем-то вроде `` базового класса '', и на самом деле вы будете отправлять 'член подкласса', то есть другая структура (например, sockaddr_in), и ядро полагается на поле, определяющее, какой тип вы передали в том же месте, что и в sockaddr.
В gcc SVN есть оптимизация реорганизации структуры (-fipa-struct-reorg), но она требует анализа всей программы и на данный момент не очень эффективна.
Стандартный gcc 10 лет спустя (версия 7.2, упакованная Ubuntu 17.10) не документирует этот параметр на странице руководства. Как ни странно, строка параметров распознается исполняемым файлом gcc.
Не говорю, что это хорошая идея, но вы, безусловно, можете написать код, основанный на порядке членов структуры. Например, в качестве взлома часто люди приводят указатель на структуру как тип определенного поля внутри, к которому они хотят получить доступ, а затем используют арифметику указателя, чтобы добраться туда. Для меня это довольно опасная идея, но я видел, как она использовалась, особенно в C++, чтобы заставить переменную, которая была объявлена частной, быть общедоступной, когда она находится в классе из сторонней библиотеки и не инкапсулируется публично. Изменение порядка членов полностью сломало бы это.
Я считаю, что ядро Linux делает это для связанных списков.
Возможно, вы захотите попробовать последнюю версию магистрали gcc или struct-reorg-branch, которая находится в стадии активной разработки.
Вы можете попробовать опцию
-fipa-struct-reorgв struct-reorg-branch. Есть ли ключевое слово GCC, позволяющее переупорядочивать структуру?