Чому компілятор видає це застереження: “відсутній ініціалізатор”? Хіба структура не ініціалізована?


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:

Висновок, хоча - ініціалізація структури просто {0}, насправді нуль ініціалізує все.

Стандарт C99 в 6.7.8 / 21 "Ініціалізація - сематика" говорить наступне:

Якщо в списку, укладеному в фігурні дужки, менше ініціалізаторів, ніж елементів або членів агрегату, або менше символів у рядковому літералі, який використовується для ініціалізації масиву відомого розміру, ніж елементів у масиві, решта агрегату повинна ініціалізуватись неявно так само, як і об’єкти, які мають статичну тривалість зберігання.

C90 говорить по суті те саме в 6.5.7 з дещо іншим формулюванням (іншими словами, C99 не додав тут чогось нового).

Також зверніть увагу, що в C ++ це було розширено, щоб порожній набір фігурних дужок, " {}", виконував ініціалізацію значення для об'єкта, оскільки були ситуації (наприклад, шаблони), коли ви навіть не знали, які члени або скільки членів типу може мати. Тож це не тільки хороша практика, але часом необхідне наявність списку ініціалізаторів, який коротший за кількість членів об’єкта.


19
Мені довелося додати, -Wno-missing-field-initializersі -Wno-missing-bracesтак, що GGC перестав стогнати про те, що я ставлю = {0};свої конструкції. Хтось знає, якщо відключення цих попереджень пропустить попередження щодо інших речей, крім = {0};структур?
Matt Clarkson,

4
Виправлення присутнє у gcc 4.7.0 , але не gcc 4.6.3 .
сплайсер

1
@splicer: Яке виправлення? Також я складаю mingw32-g++.exe (GCC) 4.7.2та отримую це попередження з наведеної вище ідіоми (навіть точного випадку STARTUPINFO).
Ян Гудек,

2
@ Ян Худек: Редакція 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 року це не повинно бути в коді будь-якої небезпечної ситуації. До речі, я вважаю цю відповідь найкращою!
Пітер ВАРГА

@AlBundy На жаль, все ще є деякі компілятори, які використовують ініціалізацію C ++ 98 (наприклад, 32-розрядний режим C ++ Builder XE5, який я зараз відкрив випадково)
MM

Через це мені довелося додати до свого файлу 10+ рядків коду. Я справді злий. Спробував передати анонімні об'єкти у виклику функції. Якщо я використовував {} або {0}, я отримав це попередження (трактується як помилка). Якщо я використовував (), то gcc вважає, що це виклик функції ...
bencemeszaros

15

Ви просили якомога більше попереджень, використовуючи -Wall -Wextra.

У цьому випадку ви отримуєте попередження, яке повідомляє, що ви не вказали всі поля, що є цілком дійсним, але могло бути ненавмисним.

Ви можете придушити це попередження, додавши -Wno-missing-field-initializers


12

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

Як робоче рішення, моє поточне рішення полягає у вибірковому придушенні цього попередження:

На жаль, це працює лише в кланг, і, здається, не працює в GCC.


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; тому я не знаю, чи може це спричинити якісь інші попередження у вашому випадку. Таким чином вам не потрібно вимикати попередження.

Приклад:

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.