This compiles without warnings using clang.
typedef struct {
int option;
int value;
} someType;
someType *init(someType *ptr) {
*ptr = (someType) {
.option = ptr->option | ANOTHEROPT,
.value = 1
};
return ptr;
}
int main()
{
someType *typePtr = init( &(someType) {
.option = SOMEOPT
});
// do something else with typePtr
}
Is this even valid C?
If so: What is the lifetime of the compound literal?
It's valid C in C99 or above.
C99 §6.5.2.5 Compound literals
The value of the compound literal is that of an unnamed object initialized by the initializer list. If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.
In your example, the compound literal has automatic storage, which means, its lifetime is within its block, i.e, the main()
function that it's in.
Recommended reading from @Shafik Yaghmour:
Yu Hao has answered with the standard, now some vulgarization.
Whenever you see a compound literal like:
struct S *s;
s = &(struct S){1};
you can replace it with:
struct S *s;
struct S __HIDDEN_NAME__ = {1};
s = &__HIDDEN_NAME__;
So:
main.c
#include <assert.h>
struct S {int i;};
/* static: lives for the entire program. */
struct S *s1 = &(struct S){1};
struct S *s2;
struct S *s3;
struct S *s4;
int f(struct S *s) {
return s->i + 1;
}
int main() {
/* Undefined behaviour: not defined yet.
* GCC 10 -fsanitize=undefined -ggdb3 -O0 -std=c99 gives at runtime:
* runtime error: member access within null pointer of type 'struct S' */
#if 0
assert(f(s2) == 1);
#endif
/* Lives inside main, and any function called from main. */
s2 = &(struct S){1};
/* Fine because now instantiated. */
assert(f(s2) == 2);
/* Only lives in this block. */
{
s3 = &(struct S){1};
/* Fine. */
assert(f(s3) == 2);
}
{
/* On GCC 10 -O0, this replaces s3 above due to UB */
s4 = &(struct S){2};
}
/* Undefined Behavior: lifetime has ended in previous block.
* On GCC 10, ubsan does not notice it, and the assert fails
* due to the s4 overwrite.*/
#if 0
assert(s3->i == 1);
#endif
}
Full compilation command:
gcc -fsanitize=undefined -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With