Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C optimization: Why does the compiler treat an object not as constant?

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.

like image 278
Marc Avatar asked Oct 30 '22 00:10

Marc


1 Answers

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

like image 106
prl Avatar answered Nov 12 '22 10:11

prl