C и C++: частичная инициализация автоматической структуры

Например, если somestruct имеет три целочисленных члена, я всегда думал, что это нормально делать в функции C (или C++):

somestruct s = {123,};

Первый элемент будет инициализирован 123, а последние два - 0. Я часто делаю то же самое с автоматическими массивами: int arr[100] = {0,}; так что все целые числа в массиве инициализируются в ноль.


Недавно я прочитал в Справочном руководстве по GNU C, что:

Если вы не инициализируете структурную переменную, эффект зависит от того, имеет ли она статическое хранилище (см. Спецификаторы класса хранения) или нет. Если это так, члены с целочисленными типами инициализируются с 0, а члены-указатели инициализируются как NULL; в противном случае значение членов структуры является неопределенным.


Может кто-нибудь сказать мне, что говорят стандарты C и C++ относительно частичной автоматической структуры и автоматической инициализации массива? Я делаю приведенный выше код в Visual Studio без проблем, но я хочу быть совместимым с gcc/g++ и, возможно, другими компиляторами. Спасибо

5 ответов

Решение

Связанная документация gcc не говорит о частичной инициализации, она просто говорит о (полной) инициализации или об отсутствии инициализации.

Что такое частичная инициализация?

Стандарты не определяют частичную инициализацию объектов, либо есть полная инициализация или отсутствие инициализации. Частичная инициализация - это нестандартная терминология, которая обычно относится к ситуации, когда вы предоставляете некоторые инициализаторы, но не все, а именно: Меньше инициализаторов, чем размер массива или число инициализируемых элементов структуры.

Пример:

int array[10] = {1,2};                    //Case 1:Partial Initialization

Что такое (полная) инициализация или нет инициализации?

Инициализация означает предоставление некоторого начального значения создаваемой переменной в то же время, когда она создается. то есть: в том же коде оператора.

Пример:

int array[10] = {0,1,2,3,4,5,6,7,8,9};    //Case 2:Complete Initialization
int array[10];                            //Case 3:No Initialization

Цитируемый параграф описывает поведение для Case 3,

Правила, касающиеся частичной инициализации (Case 1) хорошо определены стандартом, и эти правила не зависят от типа хранения инициализируемой переменной.
AFAIK, Все основные компиляторы имеют 100% соответствие этим правилам.


Может кто-нибудь сказать мне, что говорят стандарты C и C++ относительно частичной автоматической структуры и автоматической инициализации массива?

Стандарты C и C++ гарантируют, что даже если целочисленный массив находится в автоматическом хранилище и если в списке, заключенном в скобки, меньше инициализаторов, то неинициализированные элементы должны быть инициализированы в 0,

Стандарт С99 6.7.8.21

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


В C++ правила изложены с небольшой разницей.

C++ 03 Стандарт 8.5.1 Агрегаты
Параграф 7:

Если в списке меньше инициализаторов, чем элементов в агрегате, то каждый элемент, который не был явно инициализирован, должен быть инициализирован по значению (8.5). [Пример:

 struct S { int a; char* b; int c; };
 S ss = { 1, "asdf" };

инициализирует ss.a с 1, ss.b с "asdf", а также ss.c со значением выражения формы int(), то есть,0, ]

Хотя инициализация значения определяется в
C++03 8.5 Инициализаторы
Параграф 5:

Инициализировать значение объекта типа T означает:
- если T является типом класса (раздел 9) с конструктором, объявленным пользователем (12.1), то вызывается конструктор по умолчанию для T (и инициализация некорректна, если у T нет доступного конструктора по умолчанию);
- если T является типом класса без объединения без конструктора, объявленного пользователем, то каждый нестатический член данных и компонент базового класса в T инициализируются значением;
- если T является типом массива, то каждый элемент инициализируется значением;
- иначе объект инициализируется нулями

В C объекты никогда не инициализируются частично - если какая-либо их часть инициализируется, весь объект (и все дочерние объекты рекурсивно) инициализируются. Если явный инициализатор не предоставлен, то элементы инициализируются как "ноль соответствующего типа".

Цитата в вашем вопросе относится к тому моменту, когда инициализатор для всего объекта полностью исключен, а не к тому моменту, когда у субобъекта отсутствует инициализатор. Например, предполагая, что arr имеет автоматическое время хранения, то это:

int arr[100] = { 123 };

инициализируется arr[0] в 123 и любой другой элемент arr в 0, Тогда как это:

int arr[100];

оставляет каждый элемент arr неинициализированный. Это последний случай, на который ссылается цитата.

Новейшие версии gcc также позволяют "частично" инициализировать и обнулить одновременно:

typedef struct{
  int a,b,c;
}T;

T s = {0, .b=5};

члены структуры теперь будут иметь следующие значения: a=0, b=5, c=0

У меня нет никакой информации о том, позволяют ли это другие компиляторы:p

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

Если переменная размещена в Heap, компилятор также не инициализирует ее.

// You can use something like this:
typedef struct {

    ...;

    ...;

} somestruct;

// Declaration of struct
somestruct st;

// Initialising with 0. It does not depend on the size of the
// structure and the number of elements in it.
// memset() initialisation doesn't care if struct is static or dynamic.
// but don't forget to use st instead &st to dynamic.
memset(&st, 0, sizeof(somestruct));
Другие вопросы по тегам