C优化:为什么编译器将对象视为常量?

时间:2017-10-11 06:51:09

标签: c gcc assembly compiler-optimization

编译以下C模块

static const int i = 1;

void f (const int *i);

int g (void)
{
  f (&i);
  return i;
}

在x86_64机器上使用gcc -S -O3会为函数g生成以下程序集:

g:
        leaq    i(%rip), %rdi
        subq    $8, %rsp
        call    f@PLT
        movl    $1, %eax           # inlined constant as an immediate
        addq    $8, %rsp
        ret

换句话说,return语句被编译为将常量$1移动到返回寄存器%eax中,这是有道理的,因为i被声明为常量。

但是,如果我删除const以便我

static int i = 1;

void f (const int *i);

int g (void)
{
  f (&i);
  return i;
}

gcc -S -O3的输出突然变为:

g:
        leaq    i(%rip), %rdi
        subq    $8, %rsp
        call    f@PLT
        movl    i(%rip), %eax     # reload i
        addq    $8, %rsp
        ret

也就是说,在调用f之后,会从内存中显式加载返回值。

为什么会这样? f的参数被声明为指向常量int的指针,因此不应允许f改变i。此外,f无法调用通过非const引用修改i的函数,因为唯一的此函数可能是g,因为i被声明为静态。

2 个答案:

答案 0 :(得分:4)

将指向const的指针强制转换为指向非const的指针并修改引用的对象并不是未定义的行为,只要引用的对象未声明为const。

6.7.3p6说:“如果尝试通过使用具有非const限定类型的左值来修改使用const限定类型定义的对象,则行为是未定义的。”

答案 1 :(得分:-2)

改变这种情况。身体是众所周知的无需特殊操作。

spring.datasource.platform=h2