This code snippet prints the value 5. I don't understand why.
#include <stdio.h>
struct A
{
int x;
};
struct B
{
struct A a;
int y;
};
void printA(struct A *a)
{
printf("A obj: %d\n", a->x);
}
int main(void)
{
struct B b = {
{
5
},
10
};
struct A *a = (struct A*)&b;
printA(a);
printf("Done.\n");
return 0;
}
When I create b, a pointer to it would point to the data { {5}, 10 }.
When I cast &b to struct A*, I'm assuring the compiler that this struct A* points to a struct of a single data element of data type int. Instead, I'm providing it a pointer to a struct of two data elements of data types struct A, int.
Even if the second variable is ignored (since struct A has only one data member) I am still providing it a struct whose member is of data type struct A, not int.
Thus, when I pass in a to printA, the line a->x is performed, essentially asking to access the first data element of a. The first data element of a is of data type struct A, which is a type mismatch due to the %d expecting a digit, not a struct A.
What exactly is happening here?
The language-lawyer explanation of why the code is fine:
As a special case, a pointer to a struct type is equivalent to a pointer to its first member. The relevant part of C17 6.7.2 §15 says:
A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa.
This means that (struct A*)&b is fine. &b is suitably converted to the correct type.
There is no violation of "strict aliasing", since we fulfil C17 6.5 §7:
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, ...
- an aggregate or union type that includes one of the aforementioned types among its members
The effective type of the initial member being struct A. The lvalue access that happens inside the print function is fine. struct B is also an aggregate type that includes struct A among its members, so strict aliasing violations are impossible, regardless of the initial member rule cited at the top.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With