Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added new examples to help explain the difference between C11 and C99. Removed some C99 examples that seemed redundant. Edited the lead in text to hopefully add some clarity to "temporary lifetime".

The C Standard states in Section 6.2.4 p8 that The C11 Standard introduced a new term "temporary lifetime", modifying an object with temporary lifetime results in undefined behavior, see Clause 6.2.4 p8.

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.

This definition differs from the C99 Standard (which defines modifying the result of a function call or accessing it after the next sequence point as undefined behavior) because a temporary object's lifetime ends when the evaluation containing the full expression or full declarator ends, so the result of a function call can be accessed.  This extension to the lifetime of a temporary also removes a quite change to C90 and improves compatibility with C++. 

C functions may not return entire arrays; however, they may return functions can return a pointer to an array, and return structs or unions that contain arrays. Consequently, if a function call's return value contains an array, that array should never be modified within the expression containing the function call. In C99, it this array should also never be accessed.

Noncompliant Code Example (C11)

The following noncompliant C11 code attempts to retrieve an array and increment the first value from a struct that is returned by a function call. Because the array is being modified, the attempted retrieval results in undefined behavior.to use the indeterminate value of the pointer p. The following is compliant C99 code:

Code Block
bgColor#FFCCCC
langc
#include <stdio.h>

struct X { int a[65]; };

struct X addressee(void) {
  struct X result = { 1, 2, 3, 4, 5, 6 };
  return result;
}

int main(void) {
  printf("%x", ++(addressee().a[0]));
  return 0;
}

Compliant Solution

 f();
int *p = f().a;
printf("%p\n", p);

Compliant Code Example (C11)

The following code is C11 compliant; however it is noncompliant C99 code having undefined behavior because the sequence point preceding the call to printf comes between the call and the access by printf of the string in the returned objectThis compliant solution stores the structure returned by the call to addressee() as my_x before calling the printf() function:

Code Block
bgColor#ccccff#FFCCCC
langc
#include <stdio.h>

struct X { intchar a[68]; };

struct X addresseesalutation(void) 
{
  	struct X result = { 1, 2, 3, 4, 5, 6 "Hello" };
  	return result;
}

intstruct X mainaddressee(void) 
{
  	struct X my_xresult = addressee();
  printf("%x", ++(my_x.a[0]));
   { "world" };
	return result;
}

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

Noncompliant Code Example (

...

C11)

The following noncompliant code attempts to retrieve an array and increment the first value from a struct that is returned by a function call:. Because the array is being modified, the attempted retrieval results in undefined behavior.

Code Block
bgColor#FFCCCC
langc
#include <stdio.h>

struct X { charint a[6]; };

struct X addressee(void) {
  struct X result = { "world"1, 2, 3, 4, 5, 6 };
  return result;
}

int main(void) {
  printf("Hello, %s!\n%x", ++(addressee().a[0]));
  return 0;
}

This solution is problematic in C99 because of three inherent properties of C:

...

Consequently, when printf() tries to dereference the pointer passed as its second argument, it is likely to find garbage.

Note that the behavior of this code in the C Standard is defined, because the lifetime of temporary objects extends to the full expression containing it.

Implementation Details

This code compiles cleanly and runs without error under Microsoft Visual C++ Version 8.0. On the GCC compiler version 4.2, the program compiles with a warning when the -Wall switch is used, and execution on Linux results in a segmentation fault. However, if the flag --std=c99 is passed to the GCC compiler, the program compiles with no warning and runs with no error.

...

Compliant Solution (C11)

This compliant solution stores the structure returned by the call to addressee() as my_x before calling the printf() function:

Code Block
bgColor#ccccff
langc
#include <stdio.h>

struct X { charint a[6]; };

struct X addressee(void) {
  struct X result = { "world" 1, 2, 3, 4, 5, 6 };
  return result;
}

int main(void) {
  struct X my_x = addressee();
  printf printf("Hello, %s!\n%x", ++(my_x.a[0]));
  return 0;
}

Risk Assessment

Attempting to access or modify an array within a function after a subsequent sequence point may result in unexpected and perhaps unintended program behavior.

...