Страницы

Поиск по вопросам

пятница, 20 декабря 2019 г.

Оптимизация выравнивания компиляторами

#cpp #c #выравнивание


Следующие структуры имеют одинаковые поля.

struct A {
    char a;
    char c;
    double b;
};

struct B {
    char a;
    double b;
    char c;
};


Но их размер будет отличаться. Как именно - зависит от архитектуры. У меня это 16
и 28 байт соответственно. 

Почему так происходит - я понимаю. Вопрос в том, почему компиляторы не делают такой,
казалось бы, банальной и очевидной оптимизации? Проверял на minGW и clang
    


Ответы

Ответ 1



Это скорее традиция, чем необходимость. Язык мог бы дать разработчику средства управлять точным выравниванием, и разрешать или запрещать перестановку членов структуры при необходимости. В начале истории языка количество байт padding'а было очевидно, т. к. архитектура была известна разработчику. Это позволяло определять бинарные форматы таким образом, что лэйаут байт в файле или отображение регистров устройства прямо соответствует расположению полей структуры в памяти. Таким образом, работу с файлами и устройствами можно организовывать через blitting, без копирования и разбора. Чтобы гарантировать отсутствие сюрпризов от оптимизатора, стандарт C запрещает перестановку полей. Ссылка на стандарт, параграф 6.7.2.1/15: 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. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning. Поскольку сейчас существует довольно много кода, который опирается на этот факт, ослаблять требования комитет по стандартизации будет вряд ли. Тем не менее, в качестве расширения языка GCC умеет переставлять поля структур, если его об этом хорошо попросить. (В последних официальных версиях эта фича выключена, но можно собрать себе GCC из экспериментальной ветки.)

Ответ 2



C++ произошел от языка C, который приближен к архитектуре компьютеров. Фактически язык C считается языком ассемблера среди языков высокого уровня. Поэтому порядок расположения членов данных класса порой очень важен, так как класс может отображаться на физическую структуру данных компьютера. Компилятор самовольно не меняет расположение членов в классе, которые имеют один и тот же класс доступа тем более как в стандартно-размещаемых классах. Поэтому об оптимизации должен позаботиться программист, если для него порядок расположения членов данных в структуре не важен, а важно их более компактное размещение. Если есть возможность, то всегда старайтесь члены данных структуры с более строгим выравниванием помещать в начало структуры

Ответ 3



Думаю, для соответствия интерфейсам. Аналогично аппаратному соответствию, описанному в других ответах, можно упомянуть и программные интерфейсы. Интерфейс подразумевает одинаковую трактовку параметров с обеих сторон. Несоответствие порядка и типа аргументов легко отследить, пока обе стороны (передающая аргументы и принимающая) транслируются одним компилятором. Но если передающая и принимающая функции не входят в состав одного модуля? К примеру, некоторые функции WinAPI принимают параметрами структуры. Если бы каждый компилятор по своему усмотрению мог бы переставлять поля структур, то передача структур между программами и библиотеками была бы похожей на лотерею. Ведь если компилятор библиотеки и компилятор использующей её программы применили бы разный алгоритм оптимизации (переставили бы поля структур в разном порядке), то по ожидаемому смещению программа иногда получала бы значения совершенно других полей.

Комментариев нет:

Отправить комментарий