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
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • 4
    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? – Some programmer dude Dec 07 '17 at 09:40
  • 1
    @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. – Petr Skocik Dec 07 '17 at 10:06
  • 1
    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. – Lundin Dec 07 '17 at 10:48
  • 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`. – Lundin Dec 07 '17 at 11:02
  • @Lundin 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.) – Petr Skocik Dec 07 '17 at 11:13
  • 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? – Lundin Dec 07 '17 at 12:11
  • 3
    @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. – Eric Postpischil Dec 07 '17 at 12:57
  • 1
    https://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. – Stargateur Dec 07 '17 at 13:06
  • @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. – supercat Dec 15 '17 at 21:08

2 Answers2

5

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

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
-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.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • 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. – Eric Postpischil Mar 03 '23 at 00:02
  • @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. – supercat Mar 03 '23 at 02:50
  • @EricPostpischil: Do you like the revised example better? – supercat Mar 06 '23 at 15:48