Lifetime of referenced compound array literals
Asked Answered
S

1

5

I only recently learned that I can actually use references to compound literal arrays in C, which I find useful, but I don't quite understand how it works.

For instance, say that I use the feature to avoid having to declare a variable for a call some socket interface function where I don't care about the return name length, like this:

int sockfamily(int fd)
{
    struct sockaddr_storage ss;

    getpeername(fd, (struct sockaddr *)&ss, (socklen_t [1]){sizeof(ss)});
    return(ss.ss_family);
} 

Clearly, sizeof(ss) needs to actually be stored on the stack in order for a pointer to it to be passed to getpeername, and space on the stack must therefore be allocated and reserved for that purpose, but what is the lifetime of this allocation? How long can I trust it to remain allocated?

Looking at the assembly output of GCC, I observe that if I put the call to getpeername in a loop, the allocation does not survive for multiple iterations of the loop, but what other conditions, then, might cause it to cease to exist?

Sidras answered 19/2, 2013 at 10:28 Comment(1)
For struct: #21883064Stellastellar
O
13

A compound literal defined within a function has automatic lifetime associated with the block that contains it (i.e. the same lifetime as a variable declared on the same level). This is specified in the standard, paragraph 6.5.2.5p5.

int f() {
    for (int i = 0; i < 10; ++i) {
        int *j = (int []){i};  // storage duration of loop body
    }
} 

This essentially means that a compound literal is equivalent to a variable declared and initialized in the same scope:

int f() {
    for (int i = 0; i < 10; ++i) {
        int __unnamed[] = {i};
        int *j = __unnamed;
    }
} 

Take care if passing compound literals anywhere their pointers could persist past their lifetime:

int f() {
    int *p;
    if (1) {
        p = (int []){0, 1, 2};
        assert(p[0] == 0);
    }
    // *p is undefined
}
Odeen answered 19/2, 2013 at 10:37 Comment(6)
Thanks for the reference to the standard! That is very helpful.Sidras
Given something like void blah(void) { struct foo *f; ... foo = somefunc(); if (foo==NULL) f=(struct foo*){data}; ...} would there be any clean way to have the if control more than one statement?Longsuffering
@Longsuffering if I understand correctly, you could try something like struct foo *fallback[] = {data}; if (f==NULL) f=fallback; - but then you wouldn't need a compound literal.Odeen
@ecatmur: That's my point. I see no way to have compound literals behave as lvalues without introducing semantic difficulties, except in cases where they can be (and are) made const static. I wonder how much real-world code would be broken if the standard were changed such that compound literals would be const static lvalues if all their members were constants, and could otherwise be regarded as rvalues [with compilers being allowed to have the latter situations yield temporary lvalues, but with such use being deprecated]?Longsuffering
@ecatmur: For the scenario where the type does not contain a VLA, but the values are non-constant, I could see some usefulness to having compound literals be lvalues which are (for purposes of lifetime) hoisted to function scope, but having them be lvalues of shorter lifetime seems to me like a worst-of-all-worlds solution. Being able to define const static items other than strings within a macro would be represent semantics not otherwise obtainable and shouldn't be hard for a compiler (the handling would be basically equivalent to that of a string literal).Longsuffering
@ecatmur: I suspect the reason gcc's statement-within-expression extension didn't get adopted into the Standard is that some compilers may have trouble creating automatic-duration lvalues within an expression context; defining a standard means for compilers that can create automatic lvalues mid-expression to let programmers define named variables there would seem more useful than having compound literals behave as anonymous local variables.Longsuffering

© 2022 - 2024 — McMap. All rights reserved.