This question is an extension of what I have asked before. However, after a period of time, I find that some of my concepts about Conversion Behavior between Two Pointers are still ambiguous.
To facilitate the discussion, I first make the following assumptions about the host implementation:
- malloc: 8-aligned
sizeof(int)
: 4,_Alignof(int)
: 4sizeof(double)
: 8,_Alignof(double)
: 8
Question one:
void *ptr = malloc(4096); // (A)
*(int *) ptr = 10; // (B)
/*
* Does the following line have undefined behavior
* or violate strict aliasing rules?
*/
*(((double *) ptr) + 2) = 1.618; // (C)
// now, can still read integer value with (*(int *) ptr)
In my current understanding, the answer is No.
According to [6.3.2.3 #7] of C11:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. ...
and [6.5 #7] of C11:
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
- a type compatible with the effective type of the object,
- ...
Therefore, in my knowledge,
- After line (A), I allocated an object that has no declared type and didn't yet have the effective type.
- After line (B), the first 4 Bytes of the allocated object already have the effective type:
int
. - for line (C), the
ptr
is correctly aligned for thedouble
type, the pointer casting and the pointer arithmetic is legal. Because it didn't access the first 4 Bytes, it didn't break the 6.5 #7 rule.
Do I have any misunderstandings about what I have mentioned above?
Question two:
void *ptr = malloc(4096); // (A)
*(int *) ptr = 10; // (B)
/*
* Does the following line have undefined behavior
* or violate strict aliasing rules?
*/
*(double *) ptr = 1.618; // (C)
// now, shall not read value with (*(int *) ptr)
In my current understanding, the answer is also No.
According to [6.5 #6] of C11:
If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value.
So, in my knowledge, the line (C) is a subsequent access that modifies the stored value and updates the effective type of the first 8 Bytes to double
. Do I have any misunderstandings about what I have mentioned above?
The main confusion is not sure whether there is a violation of the [6.5 #7] rules:
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
- a type compatible with the effective type of the object,
- ...