复合文字的生命周期
Lifetime of a compound literal
If the compound literal occurs outside the body of a function, the
object has static storage duration; otherwise, it has automatic
storage duration associated with the enclosing block.
我将此处的 "the enclosing block" 解释为 "the innermost enclosing block" 是否正确? (因为如果它不是最里面的,那是哪一个?)
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
这似乎没有任何充分的理由。我只想称它为编译器错误。
考虑代码:
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);
}
这样的要求会极大地且不必要地破坏复合文字的有用性(因为没有它们也可以编写代码)。一个更合理的规则会表明复合文字的生命周期会延长,直到代码离开使用它的函数,或者创建它的表达式被重新执行,以先发生者为准。由于标准允许编译器以他们认为合适的方式延长自动对象的生命周期,因此编译器这样做不应被视为错误。另一方面,故意比标准要求更有用的高质量编译器可能应该明确记录这一事实。否则,未来的维护者可能会声明任何依赖于这种明智行为的程序都是 "defective",如果编译器不再支持它们,它可能会更 "efficient"。
If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.
我将此处的 "the enclosing block" 解释为 "the innermost enclosing block" 是否正确? (因为如果它不是最里面的,那是哪一个?) 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
这似乎没有任何充分的理由。我只想称它为编译器错误。
考虑代码:
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);
}
这样的要求会极大地且不必要地破坏复合文字的有用性(因为没有它们也可以编写代码)。一个更合理的规则会表明复合文字的生命周期会延长,直到代码离开使用它的函数,或者创建它的表达式被重新执行,以先发生者为准。由于标准允许编译器以他们认为合适的方式延长自动对象的生命周期,因此编译器这样做不应被视为错误。另一方面,故意比标准要求更有用的高质量编译器可能应该明确记录这一事实。否则,未来的维护者可能会声明任何依赖于这种明智行为的程序都是 "defective",如果编译器不再支持它们,它可能会更 "efficient"。