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

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

somestruct s = {123,};

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


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

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


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

Ответ 1

В связанной документации gcc не говорится о Частичной инициализации, она просто говорит о (Полная) Инициализация или Без инициализации.

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

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

Пример:

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 и С++ гарантируют, что даже если целочисленный массив находится в автоматическом хранилище, и если в списке, заключенном в скобки, меньше инициализаторов, то инициализируются неинициализированные элементы на 0.

C99 Стандарт 6.7.8.21

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


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

С++ 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. ]

Пока инициализируется значение Инициализация,
С++ 03 8.5 Инициализаторы
Параграф 5:

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

Ответ 2

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

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

int arr[100] = { 123 };

инициализирует arr[0] до 123 и каждый другой элемент от arr до 0. В то время как это:

int arr[100];

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

Ответ 3

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

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

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

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

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

Ответ 4

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

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

Ответ 5

// 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));