Dlaczego kompilator zgłasza to ostrzeżenie: „brak inicjatora”? Czy struktura nie jest zainicjowana?

79

Tworzę rodzaj nakładki na program. Do uruchomienia programu używam wywołania CreateProcess(), które między innymi otrzymuje wskaźnik do STARTUPINFOstruktury. Aby zainicjować strukturę, którą robiłem:

Podczas kompilowania programu z GCC włączającym te zestawy ostrzeżeń -Wall -Wextradaje mi ostrzeżenie, że brakuje inicjalizatora wskazującego na pierwszą linię.

Więc skończyło się na zrobieniu:

W ten sposób kompilator nie daje żadnego ostrzeżenia. Pytanie brzmi, jaka jest różnica między tymi sposobami inicjalizacji struktury? Czy przy użyciu pierwszej metody struktura nie została zainicjowana? Który byś polecił?

Shantia
źródło
1
Ostrzeżenie jest tylko takie: ostrzeżenie. W tej konkretnej sytuacji można zignorować to ostrzeżenie. Kompilator emituje ostrzeżenie, aby pomóc w przypadkach takich jak: gdy struct struct_with_four_fields x = {1, 2, 3};tylko 3 z 4 członków są inicjowane.
pmg
W moim poprzednim komentarzu 4 członek jest inicjowany na 0.
pmg
5
Ostrzeżenie o brakujących inicjatorach nie jest generalnie nierozsądne; jeśli masz strukturę z 4 członkami i zapewniasz inicjatory tylko dla 3 z nich, prawdopodobnie będzie to błąd. Ale { 0 }jest to powszechny i ​​dobrze zdefiniowany idiom do inicjowania wszystkich elementów członkowskich do zera (zdefiniowany rekurencyjnie dla każdego elementu podrzędnego) - dlatego późniejsze wersje gcc zostały zmodyfikowane, aby nie ostrzegały o tym konkretnym przypadku.
Keith Thompson
@KeithThompson o czym mówisz? Używam gcc 4.8.2 , a od tego pytania minęło pięć lat. PS był jeszcze jeden mail, do którego chciałem na koniec linkować, ale ku mojemu zdziwieniu go brakuje. Prawdopodobnie serwer pocztowy nie zapisuje wszystkich wiadomości, to smutne, poczta przydałaby się temu, kto ponownie napotka problem.
Hi-Angel,
4
@ Hi-Angel: Kiedy kompiluję mały program z gcc-4.8.1 w Solarisie, otrzymuję „ostrzeżenie: brak inicjatora”. Kiedy kompiluję ten sam program z gcc-4.8.2 na Linux Mint, nie otrzymuję ostrzeżenia. Nawiasem mówiąc, wiersz obj = {0};w wiadomości, do której utworzyłeś łącze, jest nieprawidłowy w C i gcc 4.8.2 odrzuca go jako błąd składniowy. Jeśli kompilujesz jako C ++, pamiętaj, że jest to inny język, a gcc używa innego interfejsu; poprawki w kompilatorze C gcc mogą, ale nie muszą, dotyczyć g ++.
Keith Thompson

Odpowiedzi:

87

GCC jest po prostu zbyt paranoikiem - moim zdaniem bez dobrego powodu, ale z pewnością prawdą jest, że opiekunowie GCC wiedzą o wiele więcej o niuansach C, które ja robię.

Zobacz ten mały wątek dyskusji na temat problemu na liście dyskusyjnej GCC:

Konkluzja jednak - inicjalizacja struktury po prostu {0}spowoduje zerową inicjalizację całości.

Standard C99 mówi, co następuje w 6.7.8 / 21 „Inicjalizacja - sematyka”:

Jeśli na liście w nawiasach klamrowych jest mniej inicjatorów niż elementów lub członków agregatu, lub mniej znaków w literale ciągu używanym do inicjalizacji tablicy o znanym rozmiarze niż elementów w tablicy, pozostała część agregacji powinna być zainicjowane niejawnie tak samo jak obiekty, które mają statyczny czas trwania.

C90 mówi zasadniczo to samo w 6.5.7 z nieco innym sformułowaniem (innymi słowy, C99 nie dodał tutaj czegoś nowego).

Zwróć również uwagę, że w C ++ zostało to rozszerzone tak, że pusty zestaw nawiasów klamrowych „ {}” wykonywałby inicjalizację wartości na obiekcie, ponieważ zdarzały się sytuacje (takie jak szablony), w których nawet nie wiedziałbyś, kim są członkowie lub ilu członków typ może mieć. Jest to więc nie tylko dobra praktyka, ale czasami konieczne jest posiadanie listy inicjalizującej, która jest krótsza niż liczba elementów członkowskich, które może mieć obiekt.

Michael Burr
źródło
19
Musiałem dodać -Wno-missing-field-initializersi -Wno-missing-bracesżeby GGC przestało narzekać, że stawiam = {0};na moje konstrukcje. Czy ktoś wie, czy wyłączenie tego ostrzeżenia spowoduje pominięcie ostrzeżeń dotyczących innych rzeczy niż = {0};konstrukcje?
Matt Clarkson,
4
Poprawka jest obecna w gcc 4.7.0 , ale nie w gcc 4.6.3 .
splicer
1
@splicer: Która „poprawka”? Również kompiluję mingw32-g++.exe (GCC) 4.7.2i otrzymuję to ostrzeżenie w powyższym idiomie (nawet w dokładnym przypadku STARTUPINFO).
Jan Hudec
2
@Jan Hudec: wersja 172857 . Niestety adresy URL z moich poprzednich komentarzy już nie działają. Oto bug związany z Fix: gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
splicer
9
Ja wciąż otrzymuję ostrzeżenie, nawet z gcc 4.9.3 przy użyciu pusty nawias {}lub {0}inicjatorów w moich klas C ++ /
Kamil Kisiel
21

Można to łatwo naprawić dla GCC w programach C ++, inicjując strukturę jako

  • właśnie to zrobiłem kilka dni temu
dmityugov
źródło
1
Możliwą pułapką związaną z tą odpowiedzią jest to, że w C ++ 98 nie spowodowało to zerowania pól. Zachowanie zerowej inicjalizacji zostało dodane w C ++ 03.
MM
1
@MM Dziękuję za wskazanie możliwej pułapki, ale myślę, że w grudniu 2018 roku nie powinno to już być w kodzie żadnej niebezpiecznej sytuacji. BTW, uważam, że ta odpowiedź jest najlepsza!
Peter VARGA
@AlBundy Niestety nadal istnieją kompilatory, które używają inicjalizacji C ++ 98 (np. 32-bitowy tryb C ++ Builder XE5, który mam teraz otwarty przypadkowo)
MM
Z tego powodu musiałem dodać ponad 10 linii kodu do mojego pliku. Jestem naprawdę zły. Próbowano przekazać anonimowe obiekty w wywołaniu funkcji. Jeśli użyłem {} lub {0}, otrzymałem to ostrzeżenie (traktowane jako błąd). Gdybym użył (), to gcc myśli, że jest to wywołanie funkcji ...
bencemeszaros
15

Poprosiłeś o jak najwięcej ostrzeżeń za pomocą -Wall -Wextra.

W takim przypadku otrzymasz ostrzeżenie informujące, że nie określiłeś wszystkich pól, co jest całkowicie poprawne, ale mogło być niezamierzone.

Możesz pominąć to ostrzeżenie, dodając -Wno-missing-field-initializers

ekotax
źródło
12

Ta strona internetowa szczegółowo omawia podstawowy problem: http://ex-parrot.com/~chris/random/initialise.html

Aby obejść ten problem, moim obecnym rozwiązaniem jest selektywne pomijanie tego ostrzeżenia:

Niestety, to działa tylko w clang i nie wydaje się działać w GCC.

JanX2
źródło
4
Mogę potwierdzić: #pragma GCC diagnostic ignored "-Wmissing-field-initializers"zaakceptowane przez kompilator GCC 4.2.1, ale nic nie robię. niepewny co do nowych wersji gcc
Maxim Kholyavkin
1
@speakus, mogę potwierdzić, że działa z najnowszym (w momencie pisania) gcc (7.3.0).
cydef
@cydef zgodnie z innymi komentarzami i raportami błędów, które widziałem, GCC nie ostrzega już (od GCC 5) w ogóle o tym - niezależnie od tego #pragma clang diagnostic ignored "-Wmissing-field-initializers". Powinieneś prawdopodobnie sprawdzić, czy tak jest.
WD40
1

W C ++ możesz boost::initialized_valuepozbyć się tego ostrzeżenia. Mam wyłączone ostrzeżenia dlaboost ; więc nie wiem, czy spowodowałoby to jakiekolwiek inne ostrzeżenia w twoim przypadku. W ten sposób nie musisz wyłączać ostrzeżenia.

Przykład:

Michael F. Hancock
źródło