Lifetime of a compound literal
Asked Answered
F

2

6

6.5.2.5p5 says

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.

Am I correct to interpret "the enclosing block" here as "the innermost enclosing block"? (Because if it's not the innermost one, which is it?) Why are gcc and clang behaving as if the lifetime of a literal were its enclosing function?

Example:

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);}
}

Code generated by gcc/clang at -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
Fireguard answered 7/12, 2017 at 9:36 Comment(9)
Can you perhaps elaborate on what your thoughts are on the code you show? What do you think is problematic with it? Why is it a problem? And are you asking just because of curiosity, or is there some other reason you ask? What is the actual problem that lead to this post?Evanescent
@Someprogrammerdude That compound-literal code (which I want to use because I like it better) is seemingly unnecessarily wasting my precious stack space on not 1 but 2 major optimizing compilers, which bothers me, so I want to know if there's a reason for it.Fireguard
Compound literals behave just as any other variable - their scope is restricted to the { } block where they are declared. Or if outside a function, they have file scope and static storage duration - just as any other variable. As for why you get that machine code, I don't know. Seems weird indeed. I would expect it to re-use the same stack area.Northwest
Wait... g++? C++ doesn't have compound literals. You are using some gcc extension, which may behave differently than C standard compound literals. Toss in -std=c++11 -pedantic-errors.Northwest
@Northwest Compiler Explorer only gives you g++, not gcc, so people call with -x c, but this question is only about C, not C++. (Practically, a locally generated program compiled with gcc behaves the same in this regard as the g++ -x c Compiler Explorer example.)Fireguard
Locally, (gcc/mingw with -O3) I get the same inefficient behavior for both functions, identical machine code. A lea instruction followed by an address which changes by 0x11 for each call. Weird - I can't explain this. Could it be because of ASLR?Northwest
@Lundin: Compound literals outside a function do not have file scope because they do not have scope at all. Identifiers have scope, which is where in the source they are visible. Objects have lifetime, which is when in program execution they exist. A compound literal has no identifier; there is no string of characters that is its name.Rijeka
godbolt.org/g/K3ndVp, I try with big size to see if they doing something different but not. We should not have fast conclusion about this, maybe there is a good reason. By the way your question is not very clear.Tiossem
@Lundin: Compound literals aren't declared any more than string literals are declared. I fail to see any practical disadvantage to having compound literals whose address is taken behave as though their lifetime extends at least until code leaves the enclosing function or until they are re-executed, whichever happens first, but I would see their usefulness as severely limited if the lifetime couldn't be extended beyond the nearest enclosing block.Strathspey
L
5

There does not seem to be any good reason for this. I would just call it a compiler bug.

Lockman answered 7/12, 2017 at 12:47 Comment(0)
S
-1

Consider the code:

void whatever(void)
{
    THING *p;
    ...
    p=(someCondition)&(THING){...whatever...} : ...somethingElse...;
    ...
    doSomethingWith(p);
}

The way the Standard is written, the compound literal will only be usable if the assignment to p is performed within the expression containing it, without any need for an statement to control things that can't be controlled via conditional operator alone; changing code to use an if statement rather than ?: operator would require a significant reworking:

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);
}

Such a requirement would substantially and needlessly undermine the usefulness of compound literals (since code could be written about as well without them). A far more reasonable rule would indicate that the lifetime of a compound literal extends until code leaves the function in which it was used, or the expression creating it is re-executed, whichever happens first. Since the Standard allows compilers to extend the lifetime of automatic objects however they see fit, the fact that a compiler does so should not be considered a bug. On the other hand, a quality compiler which is deliberately going to be more useful than the Standard requires should probably explicitly document that fact. Otherwise future maintainers may declare that any programs that rely upon such sensible behavior are "defective", and that the compiler can be more "efficient" if it ceases to support them.

Strathspey answered 15/12, 2017 at 20:58 Comment(3)
Per C 2018 6.8.4 3, and the same paragraph in C 2011, a substatement of a selection statement is a block. The required lifetime of the compound literal is limited to that block regardless of whether it is a compound statement or not.Rijeka
@EricPostpischil: Still bad language design. Compound literals would have been more useful if their lifetime extended until either they were re-executed or execution left the function. The stated rationale for not extending them through the execution of a function is bogus given that the issues the Committee was seeking to avoid arise if one does a goto from a location after a compound literal to a location before.Strathspey
@EricPostpischil: Do you like the revised example better?Strathspey

© 2022 - 2024 — McMap. All rights reserved.