V2651. MISRA. Initializer using chained designators should not contain initializers without designators.
This diagnostic rule is based on the MISRA (Motor Industry Software Reliability Association) software development guidelines.
This diagnostic rule is relevant only for C.
Avoid mixing chained designators and positional initialization within an object aggregate initialization. This may impair code readability or lead to unexpected issues.
When declaring objects of structures, unions, or arrays, a programmer can provide initial values for fields or elements using aggregate initialization ({ .... }
). Initializers can be of two types: positional and designated.
Positional initializers fill:
- array elements in the order of increasing index;
- structure fields in their declaration order.
Any array elements or structure fields lacking an explicit initializer will be zero-initialized. The example of positional initialization:
typedef struct
{
int x;
int y;
int z;
} TypeA;
TypeA obj = { 0, 0 }; // positional initialization
// obj == { 0, 0, 0 }
Designated initializers (designators) enable to initialize a specified array element or structure field. The example of designated initialization:
typedef struct
{
int x;
int y;
int z;
} TypeA;
TypeA obj = { .x = 1, .y = 2 }; // designated initialization
// ^~ ^~ // obj == { 1, 2, 0 }
// \_____/
// designators
If a positional initializer follows a designator, it initializes the next element or field after the designated one. Look at the example:
typedef struct
{
int x;
int y;
int z;
} TypeA;
TypeA obj = { .y = 2, 3 }; // mixed aggregate initialization
// obj == { 0, 2, 3 }
If a designator consists of a compound name, it is considered (nested/chained) and allows initializing a subobject within a structure field or array element:
typedef struct
{
int x;
int y;
} TypeA;
typedef struct
{
TypeA a;
double coeff;
} TypeB;
TypeB obj = { .a.x = -1, .coeff = 0.5 }; // obj == { { -1, 0 }, 0.5 }
// ^~~~
// \
// nested/chained designator
To enhance code readability and prevent unexpected problems, avoid using chained designators and positional initializers within the same initializers level. Look at the example with an error:
typedef struct
{
int x;
int y;
} Point;
typedef struct
{
Point center;
double radius;
int fill_color;
} Circle;
static Circle CreateRedCircle(void)
{
Circle res = { .center.x = 5,
1.0,
0xFF0000 };
return res; // Expects res == { { 5, 0 }, 1.0, 0xFF0000 }
// Actual res == { { 5, (int) 1.0 },
// (double) 0xFF0000,
// 0 }
}
The CreateRedCircle
function is used to create a red circle with the center (5; 0)
, radius 1.0
, and a red fill color. However, due to the properties of designators described above, the object will be initialized in the following way:
- the initializer
1.0
will be applied to the.center.y
field, not to.radius
; - the initializer
0xFF0000
will be applied to the.radius
field, not to.radius
; - the
.fill_color
field will be zero-initialized.
To fix the problem, use designators for every field of the object and its subobjects:
static Circle CreateRedCircle(void)
{
Circle res = { .center.x = 5,
.center.y = 0,
.radius = 1.0,
.fill_color = 0xFF0000 };
return res; // Expects res == { { 5, 0 }, 1.0, 0xFF0000 }
// Actual res == { { 5, 0 }, 1.0, 0xFF0000 }
}
Exception. A subobject initializer can omit designators in its own initializer list, but only if two conditions are met:
- the subobject initializer has no chained designators;
- no designator in the wrapping initializer list points inside this subobject.
static Circle CreateRedCircle(void)
{
Circle res = { .center = { 5, 0 },
.radius = 1.0,
.fill_color = 0xFF0000 };
return res; // Expects res == { { 5, 0 }, 1.0, 0xFF0000 }
// Actual res == { { 5, 0 }, 1.0, 0xFF0000 }
}
This diagnostic is classified as:
|