На моей рабочей машине (Windows Vista, MinGW gcc 4.3.2) ваш код не создал ассемблера для утверждений ни на одном уровне оптимизации!
Чтобы сгенерировать утверждения, мне пришлось придумать переменную volatile int
и скомпилировать с флагом -O0
.
int main(void) {
float input[MAX_INPUTS] __attribute__ ((__aligned__(16)));
static float input_static[MAX_INPUTS] __attribute__ ((__aligned__(16)));
volatile int addr_as_int;
printf("Address of input: %p\n", &input);
addr_as_int = (int)input;
print_pointer(input);
print_int(addr_as_int);
printf("normal int: %08x; int%%16: %02x\n", addr_as_int, addr_as_int%16);
printf("Assert: %d\n", (addr_as_int % 16) == 0);
assert((addr_as_int % 16) == 0); /* Passes */
printf("Address of input_static: %p\n", &input_static);
addr_as_int = (int)input_static;
print_pointer(input_static);
print_int(addr_as_int);
printf("static int: %08x; int%%16: %02x\n", addr_as_int, (addr_as_int)%16);
printf("Assert: %d\n", (addr_as_int % 16) == 0);
assert((addr_as_int % 16) == 0); /* Does not Pass */
return 0;
}
Я понятия не имею, почему компилятор решил удалить утверждения из объектного файла. Быстрый поиск в гугле ничего интересного не выявил.
Обновление 1 (добавлено @Pax по предложению @Falaina — мы все предлагаем вам принять это, если оно окажется правдой):
На самом деле я думаю, что @Falaina прибила это в комментарии к ответу @Pax:
Просто предложения. Вы компилируете с оптимизацией? Возможно, компилятор пытается быть умным и говорит: «Эй, эта переменная выровнена по 16 байтам, очевидно, адрес % 16 равен 0» и заменяет все ваши проверки на 1. Просто мысль.
Вот объяснение. GCC выясняет из исходного кода, что ввод действительно (должен быть) выровнен по 16 байтам. Это достаточно умно, чтобы вообще отбросить assert
и просто распечатать 1 вместо printf
.
Однако на этапе компоновки компоновщик не может гарантировать выравнивание до 16 байтов, вместо этого выбирая 8, потому что (от @Pax):
Обратите внимание, что эффективность выровненных атрибутов может быть ограничена внутренними ограничениями вашего компоновщика. Во многих системах компоновщик может организовать выравнивание переменных только до определенного максимального выравнивания. (Для некоторых компоновщиков максимальное поддерживаемое выравнивание может быть очень-очень маленьким.) Если ваш компоновщик может выровнять переменные только до максимального 8-байтового выравнивания, то указаниеalign(16) в __attribute__ все равно предоставит вам только 8 байтов. байтовое выравнивание. См. документацию вашего компоновщика для получения дополнительной информации.
К тому времени уже слишком поздно возвращать в код assert
и неоптимизированные printf
. Таким образом, фактический исполняемый файл не будет утверждать (поскольку они были удалены) и будет печатать оптимизированную 1, а не вычислять ее во время выполнения.
Причина, по которой volatile
исправляет это в моем ответе, заключается в том, что GCC не будет оптимизировать выражения, содержащие изменчивые компоненты. Он оставляет assert
s и правильно вычисляет аргументы printf
во время выполнения.
Вы можете вручную выровнять свой массив, если не возражаете объявить его немного больше, чем это необходимо:
#include <assert.h>
#include <stdio.h>
#define MAX_INPUTS 250
void *force_align(void *base, size_t s, int align) {
size_t x;
int k = 0;
x = (size_t)base;
while ((k < align / (int)s) && (x % align)) {
k++;
x += s;
}
if (k == align) return NULL;
#if 0
printf("%d elements 'discarded'\n", k);
#endif
return (void*)((size_t)base + k*s);
}
int main(void) {
#define ALIGNMENT_REQ 16
#define EXTRA_ALIGN_REQ (ALIGNMENT_REQ / sizeof (float))
static float misaligned_input[MAX_INPUTS + EXTRA_ALIGN_REQ]
__attribute__ ((__aligned__(ALIGNMENT_REQ)));
float *input;
/* manual alignment, check for NULL */
assert( (input = force_align(misaligned_input, sizeof *input, ALIGNMENT_REQ)) );
printf("Address of misaligned input: %p\n", misaligned_input);
printf("Address of input: %p\n", input);
printf("Assert1: %x\n", ( ((int) (input)) ) );
printf("Assert2: %x\n", ( ((int) (input)) % ALIGNMENT_REQ ) );
printf("Assert3: %x\n", ( ((int) (input)) % ALIGNMENT_REQ ) == 0 );
assert ( ( ((int) (input)) ) );
#if 0
assert ( ( ((int) (input)) % ALIGNMENT_REQ ) ); /* Fails */
#endif
assert ( ( ((int) (input)) % ALIGNMENT_REQ ) == 0 ); /* Passes */
return 0;
}
person
pmg
schedule
24.09.2009