Запросить выравнивание определенной переменной
С++ 11 представил спецификатор alignas
, чтобы указать выравнивание переменной, а alignof
оператора, чтобы запросить выравнивание по умолчанию для типа по умолчанию. Тем не менее, я не вижу никакого способа получить выравнивание определенной переменной. Возьмем следующий тривиальный пример:
alignas(16) float* array;
Вот что мы можем с этим сделать:
-
alignof(float*)
возвращает 8, что явно не то, что мы хотим.
-
alignof(array)
возвращает 16, что именно мы хотим, но это расширение компилятора; alignof
, как указано в стандарте, не может использоваться для определенной переменной.
-
alignof(decltype(array))
возвращает 8, что было вполне ожидаемым, но не тем, что мы хотим.
-
std::alignment_of
реализуется с точки зрения alignof
, поэтому это мало помогает.
Я бы хотел, чтобы механизм подтверждал, что конкретная переменная array
выровнена на границе 16 байтов. Есть ли что-нибудь в стандарте для выполнения такого запроса?
Ответы
Ответ 1
Вы можете попробовать что-то вроде:
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 *
(см. Что такое тип данных uintptr_t).
Подробнее в N4201 (он предлагает, помимо прочего, операцию is_aligned()
).
ИЗМЕНИТЬ
существует volatile
здесь?
Он позволяет что-то вроде:
alignas(16) volatile float a;
assert(is_aligned(&a, 16));
Без volatile
вы получите сообщение об ошибке
неизвестное преобразование из 'volatile float *' в 'const void *' для 1-го аргумента
Другие ссылки:
Ответ 2
В настоящее время это обрабатывается EWG 98. Я отправил статью об этом:
Спецификатор alignas
применим к объектам, что влияет на их требования к выравниванию, но не их тип. Поэтому в настоящее время невозможно определить требование фактического выравнивания объекта. В этой статье предлагается разрешить применение alignof
к объектам и ссылкам.
Лучшее, что вы можете сделать в этот момент времени, это определить отдельную переменную, содержащую выравнивание переменных.
Ответ 3
Вы можете попробовать следующее:
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;