Выравнивание класса по классу, от которого он наследуется? Принудительно выравнивать все стеки? Изменить размер?

Я хочу иметь базовый класс, который диктует выравнивание объектов, которые наследуются от него. Это прекрасно работает для кучи, потому что я могу контролировать, как это распределяется, и как массивы распределяются в шаблоне пользовательского массива. Тем не менее, фактический размер класса для C++ не меняется вообще. То есть, если я выполню арифметику с указателем над указателем производного класса, он будет пропущен в неправильном месте. Это проблема первая.

Вторая проблема - выравнивание стека. Кажется, не существует способа напрямую заставить весь стек быть 16-байтовыми указателями.

Единственное, на что я могу повлиять - это специфические настройки компилятора vC++ и g++, но проблема здесь в том, что мне не нужно постоянно исправлять выравнивание вручную. Это должно быть подвержено ошибкам, не говоря уже о боли.

Я мог бы также сделать какой-нибудь умный указатель, но это также привело бы к появлению новых проблем.

Если я просто выровняю базовый класс, будут ли выровнены и дочерние классы? Если так, это решило бы большинство моих проблем, но это кажется сомнительным (хотя я попробую это).

3 ответа

Решение

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

Тем не менее, на самом деле вы ничего не можете сделать для выравнивания стека - это полностью обрабатывается компилятором и требованиями ABI платформы компилятора. Как вы указываете, опция компилятора или, возможно, прагма может позволить вам осуществлять некоторый контроль, но ничего переносимого.

Помня ответ Михаэля относительно переносимости... Я предполагаю, что вы нацелены на векторизацию SSE и начинаете чувствовать эту боль, и это действительно должно быть стандартным способом сделать это с явными подсказками и контролем низкого уровня. Оба компилятора, о которых вы упомянули, по умолчанию стремятся к 16-байтовому выравниванию в стеке.

Таким образом, хотя поддержка компиляторов может быть различной, может быть изменена, подвергнута сомнению и т. Д., Она также может быть недостаточно использована для одного из них; это зависит от используемых вами оптимизаторов и типов и, естественно, от выбора векторизатора для здравомыслия. Опять же, неясно, что вы делаете и в чем польза.

Так как определение вашей проблемы без примера схематично, возможно, вы можете дать команду declspec(align(16)) для Калифорнии (с LTCG) и __attribute ((align (16))) для gcc. Если это поможет, было бы хорошо сообщить нам, и что конкретно работает или нет в примере, какие предупреждения или ошибки компилятора тоже. Я бы также избегал использования умных указателей по разным причинам.

sizeof в вашем вопросе означает, что вы также сталкиваетесь с проблемами, связанными с массивами переменных и типами указателей, и в этом случае первое может быть проблематичным. И даже если вы можете потерять конструктор копирования и средства назначения, проверка машинного кода не повредит. То есть, в случае осложнений, вам нужно взглянуть на вывод и в случае переключения VC++ на Intel для лучшей подсказки в Windows, а также проверить /compilet и ошибки assert/trap во время выполнения на раннем этапе или для другого выбора любой бесплатный инструмент для анализа объектных файлов. Тогда вы просто работаете с явно проблемными конструкциями самым разумным образом, что всегда возможно.

У нас была похожая проблема на PARISC HPUX, где единственной атомарной конструкцией была 4-байтовая атомарная очистка, которая требовала выравнивания 16 байт.

Мы могли бы выдумать это, объявив наше 4-байтовое количество следующим образом:

struct Stupid_HPUX
{
   int 4byteLockWordInHere [4];
};

и выбрать правильный для использования во время выполнения. Для вашей проблемы, вы могли бы сделать что-то подобное

союз rawMemory
{
   int blah[(sizeof(yourtype) + 16)/4];
   символ с [1];
} у;

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

Другие вопросы по тегам