Подтвердить что ты не робот

Частичная инициализация структуры C

В этой ссылке указано, что "когда у автоматического массива или структуры есть частичный инициализатор, остаток инициализируется до 0" . Я решил попробовать, что я прочитал, и написал следующий фрагмент кода:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    //int arr[3] = {2};  // line no. 7

    struct s {
        int si;
        int sj;
    };

    struct s myStruct;
    myStruct.si = 9;
    printf("%d\n", myStruct.sj);
}

Я не понимаю, почему 4096 (который, я считаю, является некоторым значением "мусора" ), печатается, когда я прокомментирую line no. 7, и я получаю 0, когда я раскомментирую line no. 7. Я не думаю, что объявление arr имеет какое-то отношение к записи активации main() (а точнее myStruct), которая должна выглядеть (если у нас есть line no. 7 uncommented):

---------------
|  Saved PC   |
---------------
|  arr[2]     |
---------------
|  arr[1]     |
---------------
|  arr[0]     |
---------------
|  si         |
---------------
|  sj         |
---------------

Может кто-нибудь объяснить, что мне здесь не хватает?

4b9b3361

Ответ 1

Когда вы это сделаете:

struct s myStruct;
myStruct.si = 9;

Вы не инициализируете myStruct. Вы объявляете его без инициализатора, затем запускаете инструкцию для установки одного поля.

Поскольку переменная неинициализирована, ее содержимое undefined, а чтение - undefined поведение. Это означает, что, по-видимому, несвязанные изменения могут изменить это поведение. В вашем примере добавление дополнительной переменной вызвало myStruct.sj равным 0, но нет гарантии, что это будет так.

Чтобы инициализировать переменную, вы должны дать ей значение в то время, когда оно определено:

struct s myStuct = { 9 };

Сделав это, вы увидите, что содержимое myStruct.sj установлено равным 0. Это гарантировано в соответствии с разделом 6.7.8 C стандарт (с подсветкой, характерной для этого случая):

10 Если объект с автоматической продолжительностью хранения не является инициализируется явно, его значение является неопределенным. Если объект который имеет статическую продолжительность хранения, не инициализируется явно, затем:

- если он имеет тип указателя, он инициализируется нулевым указатель;

- , если он имеет арифметический тип, он инициализируется (положительным или без знака) ноль;

- , если он является агрегатом, каждый член инициализируется (рекурсивно) в соответствии с этими правилами;

- если это объединение, первое Именованный элемент инициализируется (рекурсивно) в соответствии с этими правилами.

...

21 Если в списке, заключенном в скобки, меньше инициализаторов, чем там являются элементами или членами совокупности или меньше символов в строковый литерал, используемый для инициализации массива известного размера, чем там являются элементами в массиве, остаток от совокупности должны быть инициализированы неявно так же, как объекты, имеющие статические время хранения.

Ответ 2

В вашем случае

 myStruct.si = 9;

является assignment, не initialization. В этом случае структурная переменная (и соответствующие переменные) неинициализируется. Таким образом, вы заканчиваете чтение значения неинициализированной переменной sj, что приводит к undefined поведению.

Вы можете попробовать

struct s myStruct = {9};

чтобы увидеть неявную инициализацию в действии.

Ответ 3

Это не инициализатор - ваша структура не инициализирована, тогда вы назначаете только si. sj остается неинициализированным.

Книга относится к этому типу кода:

struct s myStruct = {9};

... где sj гарантированно будет 0.

Ответ 4

Это, в основном, более или менее полный пример для больших ответов, которые уже дали другие.

#include<stdio.h>

struct{
  int a;
  int b;
}obj1={.a=0}; //Partial initialization

typedef struct struct_B{
  int a;
  int b;
}struct_B;

int main(void)
{
  printf("obj1.b : %d\n",obj1.b);
  struct_B obj2={.b=1,.a=0,0}; // b first value is overridden here as 0 immediately follows a
  printf("obj2.b : %d\n",obj2.b);
  struct_B obj3={0}; //Partial initialization, here the '0' value is meant for a as it comes first in the declaration
  printf("obj3.b : %d\n",obj3.b);
  struct_B obj4={.a=0}; //Partial initialization
  printf("obj4.b : %d\n",obj4.b);
  return 0;
}

Вывод:

obj1.b : 0
obj2.b : 0
obj3.b : 0
obj4.b : 0