2016-03-25 4 views
33

В C++ 11 введено значение alignas specifier для указания выравнивания переменной и alignof operator для запроса выравнивания по умолчанию для типа. Тем не менее, я не вижу никакого способа получить выравнивание определенной переменной. Давайте рассмотрим следующий тривиальный пример:Запросить выравнивание определенной переменной

alignas(16) float* array; 

Вот что мы можем сделать по этому поводу:

  • alignof(float*) возвращает 8, который, очевидно, не то, что мы хотим.
  • alignof(array) возвращает 16, что является именно тем, что мы хотим, но это расширение компилятора; alignof, как указано в стандарте, не может использоваться для определенной переменной.
  • alignof(decltype(array)) возвращает 8, что ожидалось, но не то, что мы хотим.
  • std::alignment_of реализован в терминах alignof, поэтому это не очень помогает.

Мне нужен механизм, подтверждающий, что конкретная переменная array выровнена по границе 16 байт. Есть ли что-нибудь в стандарте для выполнения такого запроса?

+0

* alignof * не нужно указывать, что - он возвращает минимальный контракт в * время компиляции * - вы хотите значение * во время выполнения *. Конкретная переменная может очень хорошо быть выровнена с границей страницы *, мегабайтными границами или что-то еще во время выполнения (т. Е. Намного «лучше», чем обещали или просили). Возьмите адрес переменной и убедитесь, что она делится на нужное значение выравнивания равномерно. – tofro

+0

@tofro Правильно, я забыл указать его, но я вроде как ожидал, что 'alignof' превратится в runtime thingy при использовании в имени переменной (я думаю, это то, что делает расширение компилятора). Я не ожидал, что все будет известно во время компиляции. – Morwenn

+0

Я не могу понять, что-то вроде * # define ALIGNED8 (x) ((& (x) && 0x7) == 0) * не соответствует вашей цели или почему стандарт должен иметь что-то, что дублирует эту простую конструкцию. – tofro

ответ

8

Вы можете попробовать что-то вроде:

bool is_aligned(const volatile void *p, std::size_t n) 
{ 
    return reinterpret_cast<std::uintptr_t>(p) % n == 0; 
} 

assert(is_aligned(array, 16)); 

выше предполагает плоское адресное пространство и что арифметика uintptr_t эквивалентно арифметике на char *.

Хотя эти условия преобладают для большинства современных платформ, ни один из которых не требуется стандартом.

Это вполне возможно реализация выполнить любое преобразование при разливке void * в uintptr_t до тех пор, преобразования может быть отменено при забросе назад от uintptr_t к void * (см What is uintptr_t data type).

Дополнительная информация: N4201 (предлагается, помимо всего прочего, операция is_aligned()).


EDIT

является volatile здесь необходимо?

Это позволяет что-то вроде:

alignas(16) volatile float a; 

assert(is_aligned(&a, 16)); 

Без volatile вы получите ошибку

не известно преобразование из 'летучего флоат *' до 'сопзЬ пустота *' для 1-го аргумента

Другие ссылки:

+0

Я понимаю, почему стандартизованная функция была бы полезна, если ей нужны эти гарантии. N4201 [был отклонен] (https://issues.isocpp.org/show_bug.cgi?id=61). – Morwenn

+0

@manlio, '' volatile' необходимо здесь? И если так, разве это не должно быть 'const void * volatile'? – user5434231

+0

@ user5434231 Я добавил некоторые ссылки на ответ – manlio

2

Вы можете попробовать это:

template<size_t size, typename T> 
constexpr bool IsAlignedAs(const T& v) 
{ 
    return (reinterpret_cast<const size_t>(&v) % size) == 0; 
} 

std::cout << IsAlignedAs<16>(array) << std::endl; 
std::cout << IsAlignedAs<32>(array) << std::endl; 
+0

Кстати, вы можете использовать 'static_assert (IsAlignedAs <16> (массив),« Array un aligned to 16 »);' для вашего массива, но вы не можете использовать 'static_assert (IsAlignedAs <32> (массив)", массив не выровнен к 32 ");' поскольку он не определился во время компиляции, верно это или нет. – Elijan9

+0

Не постоянное выражение для clang. – Jarod42

+0

Действительно, это похоже на gcc. Проверка выравнивания адреса во время компиляции (до привязки его к его окончательному местоположению) уже казалась немного преждевременной ... – Elijan9

4

Это в настоящее время обрабатываются EWG 98. Я представил a paper на этом:

alignas спецификатора применит к объектам, влияющий на их требование выравнивания, но не их тип. Поэтому в настоящее время невозможно определить фактическое требование выравнивания объекта. В настоящем документе предлагается разрешить применение alignof к объектам и ссылкам.

Лучшее, что вы можете сделать в этот момент времени, это определить отдельную переменную, удерживающую выравнивание переменной.

+1

Я рад видеть, что другие люди думали об этом и начали работать над этим :) – Morwenn

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

  • Нет связанных вопросов^_^