Подтвердить что ты не робот

Запросить выравнивание определенной переменной

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

alignas(16) float* array;

Вот что мы можем с этим сделать:

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

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

4b9b3361

Ответ 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;