Почему-Wcast-align не предупреждает о приведении из char* в int * на x86?

Я понимаю, что gcc имеет опцию-wcast-align, которая предупреждает, когда указатель приведен таким образом, что требуемое выравнивание цели увеличивается.

вот моя программа:

char data[10];
int ptr = *((int *)data);

на моей машине требование выравнивания данных равно 1, тогда как для ptr-8.

почему я не получаю предупреждение?

может быть, потому, что я компилирую его для x86?

1 ответов


предупреждение никогда не будет выдано при компиляции для Linux i386 или x86-64, при использовании стандартных ABIs для этих систем. Позвольте мне объяснить вам, почему это так.

во-первых, давайте посмотрим, что документация gcc говорит о -Wcast-align :

предупреждать, когда указатель приведен таким образом, что требуемое выравнивание цель увеличена. Например, предупредите, если char * приведен к int * на машинах, где целые числа могут только быть доступ в два-или четырехбайтовые границы.

архитектура Intel не требует выравнивания целых чисел при использовании инструкций общего назначения. Цитирую руководство по базовой архитектуре Intel глава 4.1.1 выравнивание слов, двоичных слов, Квадвордов и двойных Квадвордов :

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

выравнивание, поэтому, строго не обязательно, хотя настоятельно рекомендуется. Однако есть одно исключение из этого правила, которое вы, возможно, имели в виду. Бит 18 в EFLAGS регистр известен как бит" проверка выравнивания " и бит 18 CR0 register известен как флаг" Маска выравнивания". Когда они оба установлены в 1, любая память обращается к данным, которые не выровнены по своей "естественной границе" (так, 2 байта для слов, 4 байта для двух слов и т. д.), приводит к #AC на Исключение Проверки Выравнивания. Если вы хотите узнать больше об этом, проверьте Руководство По Системному Программированию Intel.

, ни система V ABI для i386, ни System V ABI для x86-64 укажите, что флаг выравнивания в EFLAGS установлен. На самом деле, i386 ABI отмечает следующее на странице 29, Глава 3-3 Машинный Интерфейс :

архитектуре Intel386 не требует доступа все данные правильно выровнены. (...) Следовательно, произвольный доступ к данным, таким как указатели разыменования или ссылочные аргументы, могут быть или не быть правильно выровнены. Доступ к несоосным данным будет медленнее, чем доступ к правильно выровненным данным, но в остальном нет никакой разницы.

хотя он также рекомендует :

компиляторы должны выделять независимые объекты данных с соответствующими выравнивание.

GCC всегда знает ABI платформы, для которой он компилирует код, и - в случае x86/64-знает о том, что доступ к данным разрешен. Это почему такой код будет компилироваться без предупреждения о выравнивании (забудем о строгих правилах псевдонима в следующих примерах):

int main(void)
{
    char foo[] = "foobar";
    int bar = *(int*)(foo + 1);
    return 0;
}

если вы попытаетесь скомпилировать этот код с помощью GCC toolchain для ARM, вы получите предупреждение:

daniel@Jurij:/tmp$ arm-linux-gnueabi-gcc -Wcast-align align.c 
align.c: In function 'main':
align.c:4:13: warning: cast increases required alignment of target type [-Wcast-align]
  int bar = *(int*)(foo + 1);

это потому, что unaligned access, как правило, лучше избегать в ARM. Я не эксперт по оружию, так что больше ничего не могу сказать.

кроме того, обратите внимание, что большая часть того, что я написал, не относится к SSE / AVX.