2016-01-23 3 views
2

Один из тестов, которые мы запускаем, является компиляцией с -Wcast-align. Его особенно полезно, когда неправильный листинг возникает среди поплавков, парных и интегралов (иногда это может привести к SIGBUS, IIRC).Портативный способ сообщить компилятору, что выравнивание в порядке, не подавив предупреждение?

У нас есть код, который по существу выполняет следующее. Фактические случаи немного сложнее, но это суть использования:

typedef uint64_t word64; 

static const size_t SIZE = ...; 
word64 buffer[SIZE] = ...; 

И:

DoSomethingWithBuffer(const byte* buff, size_t size) 
{ 
    word64* ptr = (word64*)buff; 
    ... 
} 

Буфер выровнен по границе 8 или 16 байт. Я проверил выравнивание с использованием как ручных обзоров кода, так и требований времени выполнения.

Проблема как GCC, так и Clang предупреждают, что данные не выровнены. И это происходит почти в 2000 раз, поэтому я потенциально теряю реальные результаты. Например:

warning: cast from 'const byte *' (aka 'const unsigned char *') to 'word64 *' 
(aka 'unsigned long long *') increases required alignment from 1 to 8 [-Wcast-align] 
    word64 tmp = *(word64 *)inBlock^roundKeys[0]; 
        ^~~~~~~~~~~~~~~~~ 

С Clang, я могу инструмент с assert и компилятор будет иногда принимать его в качестве диагностического намеком. Но в этом случае он, похоже, не применяется. То есть, Clang не устанавливает соединение, которое assert(inBlock % 8 == 0); означает, что оно выровнено.

Как передать компилятору, что буфер выровнен без подавления предупреждения?

+2

1) использовать типы stdint.h фиксированной ширины. 2) что не так с 'alignas' от стандарта C? 3) ваш код может вызывать неопределенное поведение. – Olaf

+0

@Olaf - Спасибо. Наша тестовая программа достаточно полная. Мы требуем, чтобы код проходил через ворота безопасности от Clang и GCC Undefined Behavior Sanitizer, которые явно проверяют неприглаженный доступ. Мы также требуем, чтобы он прошел Valgrind, Coverity и Microsoft Enterprise Analysis. Кроме того, утверждение явно проверяет условие и не срабатывает. Поэтому я не считаю, что он страдает UB в этой конкретной области (и я надеюсь, что в каких-либо областях). – jww

+0

Ст. как это может сделать: word64 * ptr = (word64 *) ((intptr_t) buff); Но, возможно, слишком хаки? ;) – Ctx

ответ

2

В качестве существующей базы кода OP не требуется сильное совпадение типов, простое совпадение большинства типов с void*, которое успокоит предупреждения. Ref is @Ctx

void DoSomethingWithBuffer(const byte* buff, size_t size) { 
    const word64* ptr = (void*) buff; 
    ... 
} 
+1

Еще раз спасибо. Это получилось очень хорошо. мне потребовалось два дня, чтобы прояснить около 2500 + *** предупреждений *** -Wcast-align' *** (в основном в валках, например, при изменении 1 макроса фиксированных 50 результатов за раз). Из 2500+ или около того два были законными выводами. – jww

2

Это делает Clang счастливым, но добавит избыточных вычислений (так, вероятно, это не нормально для выпуска версии):

uint64_t y = *(uint64_t *)((uintptr_t)x & ~7UL); 

С GCC вы можете использовать __builtin_assume_aligned. Цитата GCC Manual:

Встроенная функция:

void * __builtin_assume_aligned (const void *exp, size_t align, ...) 

Эта функция возвращает первый аргумент, и позволяет компилятор предположить, что возвращаемый указатель по крайней мере выравнивания байт выровненных. Этот встроенный может иметь два или три аргумента, если он имеет три, третий аргумент должен иметь целочисленный тип, а если он отличен от нуля, то это означает смещение смещения. Например:

void *x = __builtin_assume_aligned (arg, 16); 

означает, что компилятор может предположить x, установлен в arg, по меньшей мере, 16 байт выравнивается, в то время как:

void *x = __builtin_assume_aligned (arg, 32, 8); 

означает, что компилятор может считать для x, установлен arg, что (char *) x - 8 is 32-байт выровненный.

Существует также patch для LLVM для реализации __builtin_assume_aligned, но это еще не объединены. Аналогичная внутренняя функция exists для компилятора Intel. Не уверен в Visual Studio.

Смежные вопросы