It seems it'd be legal to (for example) represent pointers as integers with reversed bit order, in which case the simple arithmetic above would not work.
Yes, nothing forbids that.
Even worse, the mapping can be type-dependent. The only requirement that is implementation-independent is that a round-trip reinterpret_cast
back to the original pointer type results in the original pointer value. And that's maybe not far fetched. For types with high alignment you don't really need to store the zero bits at the end and so the pointer type might be smaller. Then a simple reinterpret_cast
mapping might not provide any possible information to check alignment for these pointer types. See e.g. Do all pointers have the same size in C++? for discussion on pointer sizes and Exotic architectures the standards committees care about for exotic architectures, at least with regards to C, which also includes examples for this (Cray T90).
Of course, in your use you are using void*
specifically, which avoids this issue.
It is also possible that no integer type large enough to represent all pointer values exists, in which case intptr_t
shouldn't be available and reinterpret_cast
to any integer type will be ill-formed. That's specifically considered in the C standard, so there must have existed such C implementations or it was considered that such implementations may not be unlikely, when (u)intptr_t
where added to C.
However, in C++17 at least, basic.compound#3.4 says:
Note that the value representation of the pointer is irrelevant. It isn't required that reinterpret_cast
leaves the bytes in memory unchanged. So the implementation-defined mapping by reinterpret_cast
could be completely distinct from how integer and pointer object representations relate.
For example, on 64bit systems often the actual available address space is smaller (e.g. only 48bit). Then there are additional bits in the object representation. I could imagine the compiler/CPU using these extra bits for various purposes. Depending on that purpose the bits may or may not be part of the value representation and they may or may not be stripped or modified by reinterpret_cast
. Similarly, if a different pointer type instead of void*
was used, the compiler/CPU could use the bits that are guaranteed to be zero due to alignment requirements of the type for these purposes.
AFAICT the only guaranteed way that we can check alignment is using std::align, which if read liberally (I'm sure this is abuse of std::align) could be used like so:
The function has undefined behavior if the storage to which the input pointer points isn't contiguously at least alignment
long the way you wrote it. So the size/space parameters should probably be 1
(or 0
, see LWG 2421) instead. I see nothing in the specification that would require the size to be at least as large as the alignment.
The specification of std::align
does however seem broken to me anyway, so not sure whether that is intended to work. For example it fails to specify to which (or one-past which) object the resulting pointer points, pretending that it is possible to describe a pointer value just by the address it represents, but that's not possible since C++17.
I think it is also not in line with the definition of alignment in [basic] which doesn't assume any integer representation of addresses and only gives restrictions on when an address satisfies a supported alignment requirement. An implementation that only supports alignment 1
would e.g. be valid and then there is no definition for when an address is aligned for some other power-of-two.
If nothing else, is there a reason not to standardize std::is_aligned()?
Not that I am aware of. std::align
seems to have that functionality already as discussed above. A user-friendly wrapper around it would be simple to do, assuming the specification of std::align
is really as intended and supposed to be guaranteed to work on every implementation.
EDIT: my specific non-toy use case is I have std::byte const *ptr;. The only think I know about ptr is that it contains the object representations of 1024 ints. How can I check whether it's safe to reinterpret_cast ptr or use assume_aligned on it?
Even if you know that ptr
is correctly aligned and that the std::byte
array contains valid object representations for int
, then it is still not guaranteed that reinterpret_cast
(which must be followed by std::launder
either way) will be valid. You also need to make sure that, prior to copying the int
object representation into the storage, int
objects have been created. That can happen implicitly, e.g. if you memcpy
the object representations into the array or use std::bit_cast
to obtain the filled array into which ptr
points, but you can't assume it generally. Otherwise you might have an aliasing violation (and/or precondition violation of std::launder
). In particular if the object representations were copied into the std::byte
array by a simple per-byte assignment in a loop, then this will result in an aliasing violation.
operator &
oroperator %
to determine alignment? My justification is that if you are using pointers, and need to know alignment, you are probably not aiming for portability and can use platform specifics. – Lustratememcpy(uint8_t *, uint8_t*)
, I can copy 4 bytes at a time if both pointers are 32-bit aligned. – Lustratealignof
,alignas
,std::aligned_storage
andstd::aligned_union
are all closely related to the question. – Assyriastd::align
solution may have a problem in a situation wheremut_ptr + space
would be outside the original memory segment and aligning the pointer would fall off the edge. Possibly... Hypothetically... – Quadrangularreinerpret_cast
. I've added that – Threemasterstd::launder
. Casting touintptr_t
will probably work on every platform. – Georginageorgine