Compiling the following C module
static const int i = 1;
void f (const int *i);
int g (void)
{
f (&i);
return i;
}
using gcc -S -O3 on an x86_64 maching yields the following assembly for the function g:
g:
leaq i(%rip), %rdi
subq $8, %rsp
call f@PLT
movl $1, %eax # inlined constant as an immediate
addq $8, %rsp
ret
In other words, the return statement is compiled to moving the constant $1 into the return register %eax, which makes sense because i is declared constant.
However, if I remove that const so that I have
static int i = 1;
void f (const int *i);
int g (void)
{
f (&i);
return i;
}
the output of gcc -S -O3 suddenly becomes:
g:
leaq i(%rip), %rdi
subq $8, %rsp
call f@PLT
movl i(%rip), %eax # reload i
addq $8, %rsp
ret
That is, the return value is explicitly loaded from memory after the call to f.
Why is this so? The argument to f is declared to be a pointer to a constant int, so f should not be allowed to alter i. Furthermore, f cannot call a function that modifies i through a non-const reference because the only such function could be g as i is declared static.
It is not undefined behavior to cast a pointer to const to a pointer to non-const and modify the referenced object, as long as the referenced object is not declared const.
6.7.3p6 says: "If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined."
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