I have the following structure and "getter" function that returns a cast to an unsigned integer:
struct s {
uint32_t a;
};
void get_a(struct s *st, unsigned *ret)
{
*ret = (unsigned)st->a;
}
The following code is run:
struct s st;
uint16_t x;
st.a = 1;
get_a(&st, (unsigned *)&x);
And for x86_64, i686, armv7hl, ppc64le and other architectures x == 1, but for ppc64 x == 0. Why is this? Little- vs. big-endian?
The problem is that you have:
uint16_t x;
but then you try to write to that memory location as if it were the location of unsigned.
If you were on a system where unsigned and uint16_t are the same type, this is fine. But on other systems, such as the one you used for your code sample, you are in trouble.
First of all, this causes undefined behaviour by violating the strict aliasing rule. Variables of type uint16_t may only be written to through lvalues of type uint16_t, or a character type.
But even if it did not violate strict aliasing, you would still cause UB by writing outside the bounds of x. Probably, you are writing 4 or 8 bytes into a 2-byte memory location, so it will overflow the buffer.
There could also be UB if x is not correctly aligned for unsigned.