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