﻿# V2651\. MISRA\. Initializer using chained designators should not contain initializers without designators\.

Диагностическое правило основано на руководстве [MISRA](https://misra.org.uk/) \(Motor Industry Software Reliability Association\) по разработке программного обеспечения\.

Правило актуально только для языка C\.

Не следует комбинировать вложенные **десигнаторы** и позиционную инициализацию в пределах агрегатной инициализации объекта\. Это может ухудшить чтение кода или привести к неожиданным проблемам\.

При декларации объектов структур, объединений или массивов программист может предоставить начальные значения полей или элементов при помощи **агрегатной инициализации** \(`{ .... }`\)\. Инициализаторы могут быть двух видов: **позиционные** и **назначенные**\.

Позиционные инициализаторы заполняют:

* элементы массива в порядке увеличения индекса элемента;
* поля структуры в порядке их объявления\.

Все элементы массива или поля структур, к которым отсутствует явный инициализатор, будут заполнены нулями\. Пример позиционной инициализации:

```cpp
typedef struct
{
  int x;
  int y;
  int z;
} TypeA;

TypeA obj = { 0, 0 }; // positional initialization
                      // obj == { 0, 0, 0 }
```

**Назначенные инициализаторы** \(десигнаторы\) позволяют заполнить указанный элемент массива или поле структуры\. Пример назначенной инициализации:

```cpp
typedef struct
{
  int x;
  int y;
  int z;
} TypeA;

TypeA obj = { .x = 1, .y = 2 }; // designated initialization
//            ^~      ^~        // obj == { 1, 2, 0 }
//             \_____/
//           designators
```

Если инициализатор, следующий после десигнатора, использует позиционную форму, то будет заполнен элемент массива или поле структуры, следующие за тем, что указан в десигнаторе\. Пример:

```cpp
typedef struct
{
  int x;
  int y;
  int z;
} TypeA;

TypeA obj = { .y = 2, 3 }; // mixed aggregate initialization
                           // obj == { 0, 2, 3 }
```

Если десигнатор состоит из составного имени, то он считается **вложенным** \(**nested**/**chained**\) и позволяет инициализировать подобъект внутри поля структуры или элемента массива:

```cpp
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
```

Для улучшения читаемости кода и во избежание неожиданных проблем не рекомендуется использовать вложенные десигнаторы и позиционные инициализаторы в пределах одного уровня инициализаторов\. Рассмотрим ошибочный пример:

```cpp
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 }
}
```

Функция `CreateRedCircle` используется для создания красной окружности с центром `(5; 0)`, радиусом `1.0` и заливкой красного цвета\. Однако из\-за свойств десигнаторов, описанных выше, объект будет инициализирован следующим образом:

* инициализатор `1.0` будет применён к полю `.center.y`, а не к `.radius`;
* инициализатор `0xFF0000` будет применён к полю `.radius`, а не к `.fill_color`;
* поле `.fill_color` будет инициализировано нулём\.

Для исправления проблемы следует использовать десигнаторы для каждого поля объекта и его подобъекта:

```cpp
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 }
}
```

**Исключение**\. Инициализатор подобъекта в своём списке инициализации может опускать десигнаторы для указания элементов, если он не содержит никаких вложенных десигнаторов, и ни один из вложенных десигнаторов в обрамляющем списке инициализации не ссылается на элемент внутри этого подобъекта:

```cpp
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 }
}
```