2
votes

I don't know why the following code works fine, without gcc errors (-fstrict-aliasing -Wstrict-aliasing=1).

#include <stdio.h>

int 
main(void) 
{
    char  n = 42;
    char *p = &n;
    int  *q = (int *)p;

    *q = 10;

    printf("%d|%d\n", *p, *q);

    return 0;
}

If I follow the strict aliasing rule:

n1570, § 6.5 Expressions

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,

— 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.

But *q does not have a type compatible with *p, either a qualified version, either a signed or unsigned type corresponding, either a character type.

So, why is it allowed?

1
"— a type compatible with the effective type of the object" - both are integral types, and you don't even loose precision because you're converting from a char to an int.user529758
This is undefined behavior, *q points to a single char's worth of allocated space, you're writing sizeof(int)'s worth of data there.Mat
A character type is char, unsigned char, or signed char: This code does not violate strict aliasing rules due to the last clause. Nevertheless, it has other problems that yield undefined behavior.cmaster - reinstate monica
cmaster: as far as I understand, the lvalue expression has int type. I can't see anything that allows objects of character type to be accessed through an int lvalue.md5

1 Answers

3
votes

It is not allowed. The part of the Standard you posted shows through what types are you allowed to alias objects.

The fact that the code compiled doesn't mean it is correct. You are having three problems with the code that make it the program exhibit undefined behavior.

First is that you assigned a char pointer to an int pointer. Standard doesn't enforce their alignment and representation, so the resulting pointer is not valid.

int  *q = (int *)p;

Then you interpreted the char n object as an integer, violating strict aliasing.( Note the quote from the Standard in your question ).

*q;

Finally you wrote an int into the memory of the char object (char n), which causes an overflow because the size of an int is always larger than size of a char.

*q = 10;