Как проверить, указывает ли указатель на правильно выровненную ячейку памяти?

Учитывая, что void * для какого-либо хранилища, как проверить, указывает ли он на правильно выровненную память без какого-либо определенного поведения реализации?

Конечно, у нас есть std::align, но есть ли более эффективный способ сделать это?

template <std::size_t alignment>
inline bool is_aligned(void * ptr) noexcept {
    std::size_t max = 1u;
    return std::align(alignment, 1u, ptr, max);
}

PS: Мне нужно сделать это в стандарте, совместимом с C++, не полагаясь на какие-либо специфичные для платформы (определенные при реализации) хаки.

PPS: Я прошу прощения за мое (понимание) английского языка, это не мой родной язык.


EDIT (2018.08.24): Удалено "эффективное" из заголовка, добавлено еще больше формулировок, чтобы подчеркнуть, что я не хочу, чтобы какая-либо реализация определялась или определялась платформой.

Ответ 1

Если остаток не равен нулю при делении адреса с требуемым выравниванием, то адрес не выравнивается.

inline bool
is_aligned(const void * ptr, std::uintptr_t alignment) noexcept {
    auto iptr = reinterpret_cast<std::uintptr_t>(ptr);
    return !(iptr % alignment);
}

Это не может быть constexpr, хотя, из-за актерского состава.

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


Я ожидаю, что это понадобится только при выравнивании для типа, так что это может быть более удобным:

template<class T>
bool
is_aligned(const void * ptr) noexcept {
    auto iptr = reinterpret_cast<std::uintptr_t>(ptr);
    return !(iptr % alignof(T));
}