Обнуляет ли C ++ неуказанные значения при инициализации агрегата? - PullRequest
0 голосов
/ 06 апреля 2020

Интересный вопрос возник как побочный эффект какого-то другого вопроса о возможных различиях между тем, как C и C ++ обрабатывают (non-stati c -storage-duration):

int arr[7] = {0};

Кто-то утверждал, что в C ++ другие элементы не гарантировались равными нулю, но я не уверен, что согласен.

Теперь C11 заявляет, в 6.7.9 Initialization /19:

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

Это означает, что другие шесть элементов arr будут инициализированы нулями (поскольку static int x; инициализирует x нулями).


Я не уверен, так ли это для C ++. В стандарте C ++ 20 9.3.1 Aggregates /3 гласит:

Когда агрегат инициализируется списком инициализаторов, как указано в 9.3.4, элементы списка инициализаторов принимаются в качестве инициализаторов для элементы совокупности. Явно инициализированные элементы агрегата определяются следующим образом:

(3.1) - (несущественные вещи, связанные с назначенными списками и классами инициализатора - pax).

(3.2) - Если инициализатор list - список инициализаторов, явно инициализированные элементы агрегата являются первыми n элементами агрегата, где n - количество элементов в списке инициализатора.

Тогда /4 указывает, как работает явная инициализация, и /5 обрабатывает неявные случаи:

Для агрегата без объединения каждый элемент, который не был явно инициализирован элемент инициализируется следующим образом:

(5.1) - если элемент имеет инициализатор члена по умолчанию (10.3), элемент инициализируется из этого инициализатора.

(5.2) - в противном случае, если Элемент не является ссылкой, элемент инициализируется копией из пустого списка инициализатора (9.3.4).

(5.3) - В противном случае программа не работает ormed.

Мне кажется, что наш конкретный случай покрыт (5.2), поэтому нам нужно от go до 9.3.4, чтобы увидеть, что происходит с int, инициализированным с пустым списком. ({}). Это происходит во многих случаях, но я считаю, что первое, что соответствует:

(3.11) - В противном случае, если в списке инициализатора нет элементов, объект инициализируется значением.

И от 9.3 Initializers /8:

Инициализация значения объекта типа T означает:

(8.1) - если T является (возможно, cv -квалифицированный) тип класса (раздел 10) без конструктора по умолчанию (10.3.4) или конструктора по умолчанию, предоставленного или удаленного пользователем, тогда объект инициализируется по умолчанию;

(8.2) - если T является (возможно, cv-квалифицированным) типом класса без предоставленного пользователем или удаленного конструктора по умолчанию, тогда объект инициализируется нулями и проверяются ограничения semanti c для инициализации по умолчанию, и если T имеет нетривиальный конструктор по умолчанию, объект инициализируется по умолчанию;

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

(8.4) - в противном случае объект является инициализируется нулями.

* 10 79 * Следовательно, это 8.4, которое, по-видимому, является управляющим предложением, а это означает, что C ++ также инициализирует неявные элементы массива в ноль.

Верны ли мои рассуждения? Сможет ли C ++ при обнаружении int arr[7] = {0}; установить все элементы на ноль?

1 Ответ

2 голосов
/ 06 апреля 2020

Да. C ++ обычно поддерживает обратную совместимость с C, что позволяет включать и использовать код C. Подумайте, есть ли у вас устаревший код C, который пытается инициализировать массив, как вы описали:

int arr[7] = {0};

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

Просто для подтверждения, я скомпилировал эту программу C ++ с использованием Cygwin g ++ на x64 Windows:

int main() {
    int arr[7] = {0};
}

и затем разобранная функция main в GDB:

push   %rbp
mov    %rsp,%rbp
sub    $0x40,%rsp
callq  0x1004010d0 <__main>
movq   $0x0,-0x20(%rbp)
movq   $0x0,-0x18(%rbp)
movq   $0x0,-0x10(%rbp)
movl   $0x0,-0x8(%rbp)
mov    $0x0,%eax
add    $0x40,%rsp
pop    %rbp
retq

Как видите, программа перемещает 3 qwords и 1 dword стоимостью нули в стек. Это 28 байтов, что в моей системе составляет 7 дюймов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...