1

Is this fragment of code a violation of strict aliasing rule:

int main()
{
    short tab[] = {1,2,3,4};
    int* ps = (int*)(&tab[0]);
    int i = *ps;
}

I do know that if this was in the opposite way it would be a violation

int main()
{
    int tab[] = {1,2,3,4};
    short* ps = (short*)(&tab[0]);
    short s = *ps;
}
user2551229
  • 355
  • 5
  • 13
  • 2
    Why do you believe the cases are different? Also the code does not actually access any values, are you really asking about those exact pieces of code or something more involved? – Shafik Yaghmour Nov 19 '14 at 19:45
  • AIUI, casting any pointer type to any other pointer type is a strict aliasing violation unless you are casting between a derived and base type, or between any pointer type and `void*`. – cdhowie Nov 19 '14 at 19:47
  • @cdhowie The cast isn't a violation. Accessing the stored value is. Also there are more exceptions than these two. – T.C. Nov 19 '14 at 19:54
  • @ShafikYaghmour Yes, I forgot to dereference pointers to really violate the rule and I think that this post apply to be considered as duplicate - all is clear now. – user2551229 Nov 19 '14 at 21:16

3 Answers3

2

Casting a pointer to another (arbitrary) pointer type, as long as it's not ill-formed, doesn't constitute a violation; But accessing the pointees value after dereferencing that pointer would be.

Your cast is equivalent to a reinterpret_cast, [expr.reinterpret.cast]/7:

An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1, or if either type is void.

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

Of course that violates strict aliasing. The code is accessing values through a pointer of a different type, and it isn't char*.

int main()
{
    short tab[] = {1,2,3,4};
    int* ps = (int*)(&tab[0]);
    *ps = 3;
    if(tab[0] == 1) return 1;
    return 0;
}

The code is allowed to return 1 there. Because a write to *ps is a write to an int and according to strict aliasing rules an int pointer cannot possibly point to a short. Therefore the optimizer is allowed to see that the tab array is not modified, optimize out the if statement because it is always true, and rewrite the entire function to simply return 1.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
0

You'll get undefined behaviour in both cases if you attempt to dereference the converted pointer.

Informally, this is because the alignments of the types might be different.

Using a union; with a longer type and an array of the shorter type is one safe way of converting data.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • The pointer cast isn't UB. That's exactly what `reinterpret_cast` does. A strict aliasing violation happens when you try to access the stored value via the pointer. – T.C. Nov 19 '14 at 19:53
  • The union trick is often compiler-supported. But it is still a technical aliasing violation. – Zan Lynx Nov 19 '14 at 20:01
  • You sure about that? I'll paste up some example code tomorrow when I'm back at work. – Bathsheba Nov 19 '14 at 20:06