Explanation of the life time rule in C Standard

Viewed 1840

I'm writing a C compiler (with llvm as back-end) for practice, and the rules is followed by the C11 standard §6.2.4.

When going through the "Storage durations of objects" part, one case confused me:

¶8 A non-lvalue expression with structure or union type, where the structure or union contains a member with array type (including, recursively, members of all contained structures and unions) refers to an object with automatic storage duration and temporary lifetime. Its lifetime begins when the expression is evaluated and its initial value is the value of the expression. Its lifetime ends when the evaluation of the containing full expression or full declarator ends. Any attempt to modify an object with temporary lifetime results in undefined behavior.

I cannot imagine what the situation this case talks about, especially the array member part(As both non-lvalues with temporary lifetime, does a struct with an array member has any differences with a normal non-lvalue?) can anyone give me a code example to illustrate this?

2 Answers

Temporary values without arrays in them do not have to refer to objects with automatic (or indeed any) storage duration. Arrays are special because the array-to-pointer conversion, about the only useful operation one can perform on an array, implicitly requires that it has an address, so the compiler has to allocate memory for it (and thus implicitly for the entire object that contains it). Non-array lvalues do not have adresses.

struct a { int x; };
struct b { int y[2]; };
void foo(int*);
struct a one();
struct b two();

foo(&one().x); // not legal
foo(two().y); // legal, y has an address
struct Foo {
  int i[1]; //structure contains a member with array type
};

struct Foo getFoo() {
  struct Foo foo;
  foo.i[0] = 1;
  return foo;
}

void test() {
  // getFoo().i life time begin;
  int *p = getFoo().i; //A non-lvalue expression with structure type
  // getFoo().i is automatic storage duration and temporary lifetime
  // getFoo().i life time end;
  assert(*p == 1); // Any attempt to modify an object with temporary lifetime results in undefined behavior.
}
Related