复合文字的生命周期

时间:2017-12-07 09:36:25

标签: c gcc clang language-lawyer compound-literals

6.5.2.5p5

  

如果复合文字出现在函数体外,则   对象有静态存储持续时间;否则,它有自动   与封闭块相关的存储持续时间。

我是否正确将“封闭区块”解释为“最里面的封闭区块”? (因为如果它不是最里面的那个,那是什么?) Why are gcc and clang behaving as if the lifetime of a literal were its enclosing function?

示例:

long foo(long*);

void call_foo()
{
    {foo(&(long){42});}
    {foo(&(long){42});}
    {foo(&(long){42});}
    {foo(&(long){42});}
}

//for comparison

void call_foo2()
{
    {long x=42;foo(&x);}
    {long x=42;foo(&x);}
    {long x=42;foo(&x);}
    {long x=42;foo(&x);}
}

gcc / clang在-O3生成的代码:

call_foo:
  sub rsp, 40
  mov rdi, rsp
  mov QWORD PTR [rsp], 42
  call foo
  lea rdi, [rsp+8]
  mov QWORD PTR [rsp+8], 42
  call foo
  lea rdi, [rsp+16]
  mov QWORD PTR [rsp+16], 42
  call foo
  lea rdi, [rsp+24]
  mov QWORD PTR [rsp+24], 42
  call foo
  add rsp, 40
  ret
call_foo2:
  sub rsp, 24
  lea rdi, [rsp+8]
  mov QWORD PTR [rsp+8], 42
  call foo
  lea rdi, [rsp+8]
  mov QWORD PTR [rsp+8], 42
  call foo
  lea rdi, [rsp+8]
  mov QWORD PTR [rsp+8], 42
  call foo
  lea rdi, [rsp+8]
  mov QWORD PTR [rsp+8], 42
  call foo
  add rsp, 24
  ret

2 个答案:

答案 0 :(得分:5)

似乎没有任何充分的理由。我只是称它为编译器错误。

答案 1 :(得分:0)

考虑代码:

void whatever(void)
{
    THING *p;
    ...
    if (condition1)
      p=&(THING){...whatever...};
    ...
    doSomethingWith(p);
}

编写标准的方式,只有p的赋值由if控制的单独非复合语句执行时,复合文字才可用;更改代码,以便if控制复合语句需要进行重大的重写:

void whatever(void)
{
    THING *p,temp_thing;
    ...
    if (condition1)
    {
      temp_thing = (THING){...whatever...};
      // Or else temp_thing.field1 = value1; temp_thing.field2=value2; etc.
      p=&temp_thing;
    }
    ...
    doSomethingWith(p);
}

这样的要求会大大地和不必要地破坏复合文字的有用性(因为代码也可以在没有它们的情况下编写)。更合理的规则将表明复合文字的生命周期延长,直到代码离开使用它的函数,或者创建它的表达式被重新执行,以先发生者为准。由于标准允许编译器延长自动对象的生命周期,但他们认为合适,编译器这样做的事实不应被视为错误。另一方面,有意识地比标准要求更有用的质量编译器应该明确地记录这个事实。否则,未来的维护者可能会声明任何依赖于这种明智行为的程序都是“有缺陷的”,并且编译器可以更有效率和#34;如果它不再支持他们。