2

I think that I am misreading the standard quotation, hence I do not fully understand what's the exact intent of the wording.

Firstly, I am already aware of what alignment requirement is, but I can't figure out the exact relation between alignment requirement and casting in general, and what're the points I should care about, regarding alignment requirement, when I perform static_casting or reinterpret_casting. I think now the reader got my first question.

Secondly, there're some words in the standard quotation I spend two days to understand them but I don't. From the paragraph in:

N4885: 7.6.1.9 Static cast [expr.static.cast]

A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”, where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. If the original pointer value represents the address A of a byte in memory and A does not satisfy the alignment requirement of T, then the resulting pointer value is unspecified.

Here, they said "if the original pointer value doesn't satisfy the alignment requirement of T, then the resulting pointer value is unspecified". What really does that mean?

What's I can't understand is when does this "original pointer value" satisfies the alignment requirement of T, and when does not, to avoid such unspecified pointer value. I just need someone to explain the bold part from the above quote with simple examples; what I have to know, as a programmer, from that bold part and what I have to avoid. For example:

int i = 12;
double *pd = static_cast<double *>(static_cast<void *>(&i)); // does 'pd' has unspecified address value?.
short *ps = static_cast<short *>(static_cast<void *>(&i));   // does 'ps' has unspecified address value?.

Finally, there's a relatively same sentence I need to understand in:

N4885: 7.6.1.10 Reinterpret cast [expr.reinterpret.cast]

An object pointer can be explicitly converted to an object pointer of a different type.61 When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_cast<cv T*>(static_cast<cv void*>(v)). [Note 7: Converting a pointer of type “pointer to T1” that points to an object of type T1 to the type “pointer to T2” (where T2 is an object type and the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. — end note].

What does the standard mean by this sentence "the alignment requirements of T2 are no stricter than those of T1", what does the word "stricter than" mean.

I think if I have this static_assert expression, then maybe the alignment requirements of T2 would not be stricter than those of T1: static_assert(alignof(T1) >= alignof(T2)); Or this assertion is not true for some cases.

int i = 34;
double *pd = reinterpret_cast<double *>(&i); // does 'pd' has unspecified address value?.
short *ps = reinterpret_cast<short *>(&i);   // does 'ps' has unspecified address value?.

I am added these example to just clear what my problem lies, not to just answer the questions in the // comments

  • **Strikingly** similar questions [here](https://stackoverflow.com/q/71279357/10871073) and [here](https://stackoverflow.com/q/71278373/10871073). – Adrian Mole Feb 27 '22 at 15:42
  • @AdrianMole, I am already checked them before posting this question but it seems to have some non-standard and confusing comments and answers –  Feb 27 '22 at 15:54
  • *How can the alignment requirement be satisfied while casting a void pointer?* Because `void` does not have an alignment requirement. – Eljay Feb 28 '22 at 15:15
  • `static_assert(alignof(T1) >= alignof(T2));` Hmmm, on one of my machines, `alignof(long double)` is 12 (which is 80-bits and 2 padding bytes), and `alignof(long long)` is 8. Even though 12 >= 8, every other valid `long double*` will be an unspecified value cast as a `long long*`. (On this particular platform, the compiler **specifies** that such a cast is supported as a strong guarantee, even though the C++ standard leaves those as **unspecified values**.) – Eljay Feb 28 '22 at 17:09
  • @Eljay, an address of an object of type `T1` can be stored in a pointer of type `T2` if that address fulfills the alignment requirement of `T2`. SO why do we even need such an assertion, the assertion does not have anything to do with the fact that the result address should fulfill the alignment requirement of `T2`, the assertion actually doesn't have any guarantee to fulfill the alignment requirements. It may be helpful if we want to know if alignof(T2) is not stricter than alignof(T1). Suppose that `T2` is not stricter than `T1`. Does that means that the alignment requirement is satisfied? –  Mar 01 '22 at 16:43
  • You appear to be conflating two different things. The alignment of an object. The raw address value held by a pointer. – Eljay Mar 01 '22 at 16:49
  • Presume alignof(T2) is 1, and alignof(T1) is 4. The alignment requirement is satisfied in all cases. Presume alignof(T2) is 3, and alignof(T1) is 4. The alignment requirement is satisfied if the address of the T1 object is divisible by 3, and not satisfied if the address of the T1 object is not divisible by 3. – Eljay Mar 01 '22 at 16:56
  • *`double *pd = reinterpret_cast(&i);` // does 'pd' has unspecified address value?* What is the `&i`? Does that raw address value meet the requirements of `alignof(double)`? If so, then it is a specified pointer value. If not, then it is an unspecified pointer value. – Eljay Mar 01 '22 at 17:54
  • @Eljay . Thanks alot, and I am sorry for late replay. But I just ask, does the assertion `static_assert(alignof(T1) >= alignof(T2));` has anything to do with the fact that the alignment requirement is satisfied if the address of `T1` object is divisible by `alignof(T2)`? I mean, does the assertion guarantee that?. Presume the assertion is successes, can I now say that the alignment gets satisfied? –  Mar 07 '22 at 09:14
  • @Eljay . *`double *pd = reinterpret_cast(&i); // does 'pd' has unspecified address value?` What is the &i? Does that raw address value meet the requirements of alignof(double)?* Just an related question: suppose the alignment requirements are met, does the standard guarantees that the `pd` pointer will hold the same pointer value (address of `i`)?. And does dereferencing the cast expression yields UB? –  Mar 07 '22 at 09:45
  • Yes, if the address of `&i` complies with the alignment requirements, `pd` is guaranteed to hold a **specified** pointer value (where *specified* means it is suitable to be round-tripped back to a `int*`). Yes, dereferencing `pd` yields **UB**, because the pointer does not actually point to a `double`. – Eljay Mar 07 '22 at 14:32

1 Answers1

0

While common implementations have integer-like pointers (such that reinterpret_cast behaves like memcpy between pointers and integers and arithmetic on the pointers is reflected in the integer values), the standard as usual provides only weak guarantees to support less common architectures where pointers have other formats and/or special registers. As such, it’s impossible to observe alignment of a dynamic pointer value: the unspecified value applies if alignof(expression_type)<alignof(cast_type) unless the pointer refers to an object declared with alignas or to an object whose actual type is more strongly aligned.

This means that double* is a poor type to use for the sort of “temporary pointer storage” for which reinterpret_cast exists; fortunately, most C++ code uses templates (so this doesn’t come up), old C code uses char* (whose alignment is 1), and other code uses void* (which has no alignment), so there’s rarely an actual issue here.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76