Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Temporary Objects in C

In C11 the term temporary lifetime was defined:

C11 6.2.4p8: 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. 36) 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 am wondering why this only applies to rvalues of structure or union type which have a member of type array. What is so special about arrays?

struct x { int xx; };
struct y { int yy[1]; };

(struct x)   { 42 };    // *not* a temporary object
(struct y) { { 42 } };  // a temporary object

Why should the first object not be a temporary one while the second is?

like image 218
Max Maier Avatar asked Apr 28 '19 06:04

Max Maier


People also ask

Why are temporary objects created in C++?

Because the return value isn't copied to another object, a temporary object is created. A more common case where temporaries are created is during the evaluation of an expression where overloaded operator functions must be called. These overloaded operator functions return a user-defined type that often isn't copied to another object.

What is the use of temporary object in JavaScript?

// A temporary object is created to store the return // value. Because the return value isn't copied to another object, a temporary object is created. A more common case where temporaries are created is during the evaluation of an expression where overloaded operator functions must be called.

What is nameless temporary object in C++?

This concept is known as nameless temporary objects, using this we are going to implement a C++ program for pre-increment operator overloading. In this program, we used nameless temporary object in overloaded member function. Here, we did not create any object inside the member function.

What is the difference between an rvalue and a temporary object?

An rvalues is an expression that has no address in memory. A temporary object is an object that created and destroyed in the same expression, so typically objects that are unnamed, or created by the compiler when an implicit conversion is done.


2 Answers

The reason the restriction only applies to temporary objects that contain arrays is because the restriction is only relevant for temporary objects that contain arrays -- when you have an unnamed non-lvalue object that does NOT contain an array, you can't get an address from the object; using & is explicitly disallowed. However, when the object contains an array, and you access that array by name, you're implicitly getting the address of the first element of the array. Prior to C11, trying to do ANYTHING with that pointer was undefined behavior. With C11, you can now use the object (and the pointer), you just cannot modify it.


Note that the examples you have in the question (with compound literals) are NOT temporary objects -- compound literals are lvalues, so can have their address taken, and have static storage duration.

The main way you get temprary objects is when you have a function that returns a struct (or union) type -- when you call such a function, the returned value is a temprary object. Since it is not an lvalue, you can't use & on it, but if it contains an array, you can use the array name, and that will implicitly decay to a pointer to the array's first element.

like image 77
Chris Dodd Avatar answered Oct 19 '22 04:10

Chris Dodd


I'm not completely sure about this but here's what I understand from reading EXP35-C. Do not modify objects with temporary lifetime a few times. This isn't a great language-lawyer answer, but I'll try to explain it in simpler terms.

Normally a C function cannot return an array. However, you (try to) work around this by sticking an array in a structure, and returning that. Consider this example code:

#include <stdio.h>

struct X { char a[8]; };

struct X salutation(void) {
  struct X result = { "Hello" };
  return result;
}

struct X addressee(void) {
  struct X result = { "world" };
  return result;
}

int main(void) {
  printf("%s, %s!\n", salutation().a, addressee().a);
  return 0;
}

In C99, this program invoked undefined behavior. You're not allowed to even access the array inside of the structure. The reason is that the lifetime of the array ends when the function with the local variable returns.

In C11, they relaxed the rules a bit so you're allowed to access the array, but you're not allowed to modify it.

Because of this subtle difference, that EXP35-C rule recommends not doing either. Instead, save the array-containing structure result to a local variable:

#include <stdio.h>

struct X { char a[8]; };

struct X salutation(void) {
  struct X result = { "Hello" };
  return result;
}

struct X addressee(void) {
  struct X result = { "world" };
  return result;
}

int main(void) {
  struct X my_salutation = salutation();
  struct X my_addressee = addressee();

  printf("%s, %s!\n", my_salutation.a, my_addressee.a);
  return 0;
}
like image 21
Jonathon Reinhart Avatar answered Oct 19 '22 06:10

Jonathon Reinhart