Playing with the idea of creating new types in C using a struct, I wondered about assignment.
I was surprised that the following C program compiles and runs producing the expected output.
I had never considered that it was possible to use a cast on a struct
initializer list to assign a value to a struct
variable.
Why does this work and when was it allowed?
After a series of modifications and embellishments, I arrived at the following C source which much to my surprise, compiled with Visual Studio 2019 with Properties -> General -> C Language Standard set to Default (Legacy MSVC)
#include <stdio.h>
int main()
{
int jjR1 = 21;
long llR1 = 402;
struct JJ {
int jj1;
int jj2;
int jj3;
struct KK {
long ll1;
long ll2;
} kk;
};
struct KK kkR1 = { 501, 502 };
struct JJ x = { 0 };
printf("x.jj1 = %d x.jj2 = %d x.jj2 = %d x.kk.ll1 = %d x.kk.ll2 = %d\n", x.jj1, x.jj2, x.jj3, x.kk.ll1, x.kk.ll2);
x = (struct JJ){ 5 };
printf("x.jj1 = %d x.jj2 = %d x.jj2 = %d x.kk.ll1 = %d x.kk.ll2 = %d\n", x.jj1, x.jj2, x.jj3, x.kk.ll1, x.kk.ll2);
x = (struct JJ){ 5, 0, 23, {101, 102} };
printf("x.jj1 = %d x.jj2 = %d x.jj2 = %d x.kk.ll1 = %d x.kk.ll2 = %d\n", x.jj1, x.jj2, x.jj3, x.kk.ll1, x.kk.ll2);
x = (struct JJ){ jjR1, 0, 23, {llR1, 102} };
printf("x.jj1 = %d x.jj2 = %d x.jj2 = %d x.kk.ll1 = %d x.kk.ll2 = %d\n", x.jj1, x.jj2, x.jj3, x.kk.ll1, x.kk.ll2);
x = (struct JJ){ 0, 0, 23, kkR1 };
printf("x.jj1 = %d x.jj2 = %d x.jj2 = %d x.kk.ll1 = %d x.kk.ll2 = %d\n", x.jj1, x.jj2, x.jj3, x.kk.ll1, x.kk.ll2);
return 0;
}
The output of this simple test is:
x.jj1 = 0 x.jj2 = 0 x.jj2 = 0 x.kk.ll1 = 0 x.kk.ll2 = 0
x.jj1 = 5 x.jj2 = 0 x.jj2 = 0 x.kk.ll1 = 0 x.kk.ll2 = 0
x.jj1 = 5 x.jj2 = 0 x.jj2 = 23 x.kk.ll1 = 101 x.kk.ll2 = 102
x.jj1 = 21 x.jj2 = 0 x.jj2 = 23 x.kk.ll1 = 402 x.kk.ll2 = 102
x.jj1 = 0 x.jj2 = 0 x.jj2 = 23 x.kk.ll1 = 501 x.kk.ll2 = 502
The syntax you're using is known as a compound literal in C.
in C, a compound literal is an unnamed object defined by a parenthesized type-name followed by an initializer list. Its general form is:
(type_name) { initializer_list }
For example:
struct JJ {
int jj1;
int jj2;
};
struct JJ x;
x = (struct JJ){ 1, 2 };
Compound literals were introduced as part of the C99 standard (ISO/IEC 9899:1999), approved in 1999. Before this, the C89/C90 standards did not define such a construct.
Your example compiles because your compiler (Visual Studio 2019) supports certain C99 features even in legacy or default mode. Even though Microsoft Visual Studio historically did not fully support the C99 standard, later versions (such as Visual Studio 2019 and later) did add incremental support for some parts of C99, including compound literals.