37

C++11 introduced the alignas specifier to specify the alignment of a variable, and the alignof operator to query the default alignment of a type. However, I don't see any way to get the alignment of a specific variable. Let's take the following trivial example:

alignas(16) float* array;

Here is what we can do about it:

  • alignof(float*) returns 8, which is obviously not what we want.
  • alignof(array) returns 16, which is exactly what we want, but that's a compiler extension; alignof as specified by the standard can't be used on a specific variable.
  • alignof(decltype(array)) returns 8, which was quite expected but not what we want.
  • std::alignment_of is implemented in terms of alignof, so it doesn't help much.

I would like a mechanism to confirm that the specific variable array is aligned on a 16 byte boundary. Is there anything in the standard to perform such a query?

Morwenn
  • 21,684
  • 12
  • 93
  • 152
  • *alignof* doesn't need to provide that - it returns a minimum contract at *compile time* - You want a value *at run time*. A specific variable might very well be *aligned to a page boundary*, megabyte-boundaries, or whatever at run time (i.e. much "better" than promised or asked for). Take the address of the variable and check that it is divisible by your wanted alignment value evenly. – tofro Mar 25 '16 at 10:05
  • @tofro Right, I forgot to specify it, but I kind of half-expected `alignof` to turn into a runtime thingy when used on a variable name (I guess this is what the compiler extension does). I didn't expect everything to be known at compile-time. – Morwenn Mar 25 '16 at 10:09
  • I can't quite see whether something like *#define ALIGNED8(x) ((&(x) && 0x7) == 0)* doesn't fit your purpose or why the standard should have something that duplicates this simple construct. – tofro Mar 25 '16 at 10:15
  • Do you want to know that actual alignment or the minimal alignment that is guaranteed for a certain variable? – MikeMB Mar 25 '16 at 10:20
  • @MikeMB The obvious use case: known whether the `float` array is suitably aligned to be used with SSE. – Morwenn Mar 25 '16 at 10:20
  • @Morwenn: Maybe I wasn't clear. Its the actual vs. guaranteed part that is important. I'm asking, because the former is a runtime property, that can (on most platforms) simply be determined as shown in the answers or by tofro. The latter however would be a compiletime property and I don't know of any way to retrieve that. – MikeMB Mar 25 '16 at 10:26
  • @tofro maybe you meant `&`, but bitwise-and cannot be used on a pointer – M.M Mar 25 '16 at 10:29
  • @MikeMB I... guess I'm interested in the latter? I mean, while we need the array of `float` to be 16 byte aligned, an array of `float` that is 32 byte aligned is also suitable SSE if I'm not mistken. – Morwenn Mar 25 '16 at 10:30
  • @M.M.: The example was not intended as an answer, but rather to deliberately demonstrate *simplicity of a concept*. *reinterpret_cast* is a bit long for a comment. And the && is actually a typo, right. – tofro Mar 25 '16 at 10:40
  • 3
    @tofro: Because not all pointers are simply memory addresses. I have used a machine where that would completely not work (Prime mini-computer. Word addressed, bit offset in a trailing extension word - but bit offset could only be 0 or 8.) – Martin Bonner supports Monica Mar 25 '16 at 10:51

3 Answers3

10

You can try with something like:

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));

The above assumes a flat address space and that arithmetic on uintptr_t is equivalent to arithmetic on char *.

While these conditions prevail for the majority of modern platforms, neither of which is required by the standard.

It's entirely possible for an implementation to perform any transformation when casting void * to uintptr_t as long the transformation can be reversed when casting back from uintptr_t to void * (see What is uintptr_t data type).

Further details in N4201 (it proposes, among other things, the is_aligned() operation).


EDIT

is volatile necessary here?

It allows something like:

alignas(16) volatile float a;

assert(is_aligned(&a, 16));

Without volatile you get the error

no known conversion from 'volatile float *' to 'const void *' for 1st argument

Further references:

Community
  • 1
  • 1
manlio
  • 18,345
  • 14
  • 76
  • 126
  • I can see why a standardized function would be useful if it needs those guarantees. N4201 [has been rejected](https://issues.isocpp.org/show_bug.cgi?id=61) though. – Morwenn Mar 25 '16 at 10:23
  • @manlio, is `volatile` necessary here? And if so, shouldn't it be `const void* volatile`? – user5434231 Mar 25 '16 at 10:50
  • @user5434231 I've added some references to the answer – manlio Mar 25 '16 at 11:23
  • The cast to `uintptr_t` doesn't have to do any transform for the arithmetic not to work. Consider the old 8086 address model where a 32-bit address consisted of a 16 bit segment pointer and a 16 bit offset, and the actual physical address was segment<<4 + offset. – Martin Bonner supports Monica Mar 25 '16 at 14:14
7

This is currently handled by EWG 98. I submitted a paper on this:

The alignas specifier is applicable to objects, affecting their alignment requirement but not their type. It is therefore currently not possible to determine an object's actual alignment requirement. This paper proposes to permit application of alignof to objects and references.

The best you can do at this point in time is to define a separate variable holding the variable's alignment.

Columbo
  • 60,038
  • 8
  • 155
  • 203
3

You could try this:

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;
Elijan9
  • 1,269
  • 2
  • 17
  • 18
  • By the way, you could use `static_assert(IsAlignedAs<16>(array), "Array not aligned to 16");` for your array, but you cannot use `static_assert(IsAlignedAs<32>(array), "Array not aligned to 32");` since it is undecided at compile-time whether or not this is true. – Elijan9 Mar 25 '16 at 10:25
  • Not a constant expression for clang. – Jarod42 Mar 25 '16 at 10:34
  • 1
    Indeed it seems gcc specific. Checking the alignment of an address at compile-time (before linking it to its final location) already seemed a bit premature... – Elijan9 Mar 25 '16 at 10:48