Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compund literals storage duration in C

First question ever :)

I'm studying programming "by myself", reading "C Programming: A modern Approach" by K.N.King. In Chapter18 - Declarations, in the Q&A section, there is a question about why selection statements and iteration statements (and their "inner" statements) are considered to be blocks in C99. After a small introduction to the answer, he says:

[...]The C99 standard states that the object represented by a compund literal has static duration if the compound literal occurs outside the body of a function. Otherwise, it has automatic storage duration; as a result, the memory occupied by the object is deallocated at the end of the block in which the compound literal appears[...]

Which I think I understand. I've tried to return a pointer to a compound literal from a function, and indeed the output is wrong (or undefined I guess). My problem is the following; He gives this example:

/* Example 2 - if statements with braces */

double *coefficients, value;

if(x){
    coefficients = (double[3]) {1.5, -3.0, 6.0};
}else{
    coefficients = (double[3]) {4.5, 1.0, -3.5};
}
value = evaluate_polynomial(coefficients);

Followed by this explanation:

Each compound literal causes an object to be created, but that object exists only within the block formed by the braces that enclose the statement in which the literal appears. By the time evaluate_polynomial is called, coefficients points to an object that no longer exist. The result: undefined behavior.

And when I try exactly that same code in my computer (I'm using GCC in a Linux VM), I always get the right output. The literal does not seem to be deallocated once the "control flow" exit the if block.

Can someone elaborate a little more about this?

Thanks.

like image 664
Masfeo Avatar asked Jul 07 '20 13:07

Masfeo


People also ask

What is a compound literals in C?

In C, a compound literal designates an unnamed object with static or automatic storage duration. In C++, a compound literal designates a temporary object that only lives until the end of its full-expression.

Does C++ have compound literals?

In C++, a compound literal designates a temporary object, which only lives until the end of its full-expression. As a result, well-defined C code that takes the address of a subobject of a compound literal can be undefined in C++, so the C++ compiler rejects the conversion of a temporary array to a pointer.


2 Answers

For performance reasons, when the program reaches the end of a variable's scope (or this variable is freed), its content is not deleted. But its memory address might be reused later for storing another variable leading to an Undefined Behavior.

Hence, if you print your coefficients later in the program, they might or might not correspond to your expected value.

If you want to illustrate this you can progressively add more and more code beetween your variable's exit block and the instruction where your variable is read. At some point, your variable will likely not have the expected value.

Please carefully avoid Undefined Behaviors as they can lead to hard to reproduce bugs (e.g. program that works 99% of the time but breaks horribly 1% of the time).

like image 76
Maxime B. Avatar answered Sep 20 '22 04:09

Maxime B.


Although the C99 Standard regards compound literals as lvalues whose address may be taken, the Standard's lifetime rules for them mean that code should avoid taking the address of compound literals except in cases where the address will be immediately passed to a function that won't persist a copy of it, or taking the address of large automatic-duration compound literals whose contents will never change. Instead of doing those things, code should declare a conventional named object of appropriate type and value (static const, if the value will never change), and pass the address of that.

The stated rationale for limiting the lifetime of compound literals to block scope rather than function scope is to avoid having to allocate space for a new instance of a compound literal if the code defining it is re-executed. Given that code before a compound literal is allowed to goto a label which is in the same block as the compound literal but precedes it, however, it's necessary to allow for the possibility that executing a compound literal during the lifetime of the object created by an earlier execution of the same literal may not create a separately-allocated object; once one handles that for the "goto" scenario, that would also avoid any similar problems that would arise if compound literals' lifetime were bounded by the enclosing function.

like image 28
supercat Avatar answered Sep 21 '22 04:09

supercat