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