Почему компилятор выдает предупреждение: «отсутствует инициализатор»? Разве структура не инициализирована?

79

Я создаю своего рода интерфейс для программы. Для запуска программы я использую вызов CreateProcess(), который, помимо прочего, получает указатель на STARTUPINFOструктуру. Чтобы инициализировать структуру, которую я делал:

При компиляции программы с включением этих наборов предупреждений GCC -Wall -Wextraвыдает предупреждение о том, что отсутствует инициализатор, указывающий на первую строку.

В итоге я сделал:

Таким образом, компилятор не предупреждает. Вопрос в том, в чем разница между этими способами инициализации структуры? При использовании первого метода не инициализируется ли структура? Какой из них вы бы порекомендовали?

Шантия
источник
1
Предупреждение - это просто предупреждение. В этом конкретном случае можно проигнорировать это конкретное предупреждение. Компилятор выдает предупреждение, чтобы помочь вам в таких случаях, как: struct struct_with_four_fields x = {1, 2, 3};когда инициализированы только 3 из 4 членов.
pmg
В моем предыдущем комментарии 4-й член инициализирован как 0.
pmg
5
Предупреждение об отсутствии инициализаторов в целом не является необоснованным; Если у вас есть структура с 4 членами и вы предоставляете инициализаторы только для 3 из них, это, скорее всего, будет ошибкой. Но { 0 }это общая и четко определенная идиома для инициализации всех членов в ноль (определенная рекурсивно для каждого под-члена) - вот почему более поздние версии gcc были изменены, чтобы не предупреждать об этом конкретном случае.
Кейт Томпсон,
@KeithThompson, о чем ты говоришь? Я использую gcc 4.8.2 , и с момента вопроса прошло пять лет. PS было еще одно письмо, на которое я хотел бы в конце указать ссылку, но, к моему удивлению, его нет. Вероятно, почтовый сервер не сохраняет все сообщения, что печально, почта пригодится тому, кто снова столкнется с проблемой.
Hi-Angel
4
@ Hi-Angel: Когда я компилирую небольшую программу с gcc-4.8.1 на Solaris, я получаю «предупреждение: отсутствует инициализатор». Когда я компилирую ту же программу с gcc-4.8.2 на Linux Mint, я не получаю предупреждения. Между прочим, строка obj = {0};в сообщении, с которым вы связались, недействительна для C, и gcc 4.8.2 отклоняет ее как синтаксическую ошибку. Если вы компилируете как C ++, помните, что это другой язык, и gcc использует другой интерфейс; Исправления в компиляторе C gcc могут применяться или не применяться к g ++.
Кейт Томпсон

Ответы:

87

GCC просто чрезмерно параноик - на мой взгляд, без всяких на то оснований, но, конечно, верно, что сопровождающие GCC знают намного больше о нюансах C, чем я.

См. Эту небольшую ветку обсуждения проблемы в списке рассылки GCC:

Суть в том, что инициализация структуры с помощью just {0}фактически будет нулем инициализировать все это.

Стандарт C99 говорит следующее в 6.7.8 / 21 «Инициализация - Сематика»:

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

C90 говорит, по сути, то же самое, что и в 6.5.7, но с немного другой формулировкой (другими словами, C99 не добавил сюда ничего нового).

Также обратите внимание, что в C ++ это было расширено так, что пустой набор фигурных скобок « {}» будет выполнять инициализацию значения для объекта, потому что были ситуации (например, шаблоны), когда вы даже не знали, какие члены или сколько членов у типа должно быть. Так что это не только хорошая практика, но и иногда необходимо иметь список инициализаторов, который короче, чем количество членов, которые может иметь объект.

Майкл Берр
источник
19
Пришлось добавить -Wno-missing-field-initializersи -Wno-missing-bracesчтобы GGC перестал ныть, что я ставлю = {0};для своих конструкций. Кто-нибудь знает, пропустит ли отключение этого предупреждения предупреждения для других вещей, кроме = {0};структур?
Мэтт Кларксон,
4
Исправление присутствует в gcc 4.7.0 , но не в gcc 4.6.3 .
сварочный аппарат
1
@splicer: Какое "исправление"? Также я компилирую mingw32-g++.exe (GCC) 4.7.2и получаю это предупреждение на идиоме выше (даже в точном случае STARTUPINFO).
Ян Худек
2
@Jan Hudec: редакция 172857 . К сожалению, URL-адреса из моих предыдущих комментариев больше не работают. Вот ошибка, связанная с исправлением: gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
сплайсер
9
Я все еще получаю предупреждение даже с gcc 4.9.3 при использовании пустых скобок {}или {0}инициализаторов в моих классах C ++: /
Камил Кизиэль
21

Это можно легко исправить для GCC в программах на C ++, инициализировав структуру как

  • только что сделал именно это несколько дней назад
дмитюгов
источник
1
Возможная ошибка с этим ответом заключается в том, что в C ++ 98 не выполнялась инициализация полей нулями. Поведение с нулевой инициализацией было добавлено в C ++ 03.
MM
1
@MM Спасибо, что указали на возможную ловушку, но я думаю, что в декабре 2018 года в коде больше не должно быть опасной ситуации. Кстати, я считаю этот ответ лучшим!
Питер ВАРГА 05
@AlBundy К сожалению, все еще существуют компиляторы, использующие инициализацию C ++ 98 (например, 32-разрядный режим C ++ Builder XE5, который я открыл прямо сейчас по совпадению)
MM
Из-за этого мне пришлось добавить в свой файл 10+ строк кода. Я очень зол. Пытался передать анонимные объекты в вызове функции. Если я использовал {} или {0}, я получил это предупреждение (рассматривается как ошибка). Если бы я использовал (), то gcc
решил бы,
15

Вы запросили как можно больше предупреждений, используя -Wall -Wextra.

В этом случае вы получите предупреждение о том, что вы не указали все поля, что вполне допустимо, но могло быть непреднамеренным.

Вы можете подавить это предупреждение, добавив -Wno-missing-field-initializers

эконалог
источник
12

На этой веб-странице очень подробно обсуждается основная проблема: http://ex-parrot.com/~chris/random/initialise.html

В качестве временного решения мое текущее решение состоит в том, чтобы выборочно подавить это предупреждение:

К сожалению, это работает только в clang и, похоже, не работает в GCC.

ЯнвX2
источник
4
Могу подтвердить: #pragma GCC diagnostic ignored "-Wmissing-field-initializers"принято компилятором GCC 4.2.1, но ничего не делать. неуверен в новых версиях gcc
Максим Холявкин
1
@speakus, я могу подтвердить, что он работает с последним (на момент написания) gcc (7.3.0).
cydef
@cydef согласно другим комментариям и отчетам об ошибках, которые я видел, GCC больше не предупреждает (начиная с GCC 5) об этом вообще - независимо от #pragma clang diagnostic ignored "-Wmissing-field-initializers". Вам, вероятно, следует проверить, так ли это.
WD40
1

В C ++ вы можете использовать, boost::initialized_valueчтобы избавиться от этого предупреждения. У меня отключены предупреждения для boost; поэтому я не знаю, вызовет ли это какие-либо другие предупреждения в вашем случае. Таким образом, вам не нужно отключать предупреждение.

Пример:

Майкл Ф. Хэнкок
источник