Reputation: 1047
struct __packed element {
char val;
};
void foo(struct element arr[4], uint32_t a) {
uint32_t* i = (uint32_t*)arr;
*i = a;
}
int main(void) {
struct element arr[4] __aligned(4);
foo(arr, 5);
...
}
Pretty much as the title, is this a strict aliasing violation in C?
Assuming that arr's stored type is struct element[4]
Upvotes: 2
Views: 131
Reputation: 12047
It depends on how you will read element arr[4]
, and on how arr
was allocated.
If you will read it as
uint32_t value = *(uint32_t*)arr;
and arr
was either allocated dynamically (using malloc
), or allocated as an int32_t
object with automatic storage duration ("on the stack"),
it's OK.
If this is the case, your write changes the effective type to int32_t
.
But if you want to read using a type unrelated to uint32_t
, and not a character type, it's undefined behavior.
Also, arr
needs to be properly aligned for int32_t
. (If it was obtained using malloc
, it automatically is.)
After the question was edited, it becomes clear that it is indeed undefined behavior, because arr
is allocated as follows:
struct element arr[4] __aligned(4);
Upvotes: 3
Reputation: 16043
Yes, this (*i = a
) is a strict aliasing violation.
N1570 §6.5 p7:
An object shall have its stored value accessed only by an lvalue expression that has one of the following types: 88)
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with the effective type of the object,
- a type that is the signed or unsigned type corresponding to the effective type of the object,
- a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
- an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
- a character type.
None of the above requirements are met:
uint32_t
is not compatible with effective type char
.
No qualified types of char
used.
uint32_t
is not unsigned version of char
.
struct element
has no uint32_t
members.
uint32_t
is not a character type.
It would be legal if effective type of the original array would be uint32_t
or it would be allocated with malloc
for which effective type takes place at the assignment.
uint32_t arr;
foo((struct element*)&arr, 5); // Possible pointer conversion issues still apply
or
void * arr = malloc(4);
foo(arr, 5);
Note that uint32_t* i = (uint32_t*)arr
might also lead to undefined behaviour, if converted address cannot be stored in uint32_t*
type variable. But that is implementation specific, and thus depends on your platform.
Upvotes: 5