Inicjowanie struktury na 0

116

Jeśli mam taką strukturę:

typedef struct
{
    unsigned char c1;
    unsigned char c2;
} myStruct;

Jaki byłby najłatwiejszy sposób na zainicjowanie tej struktury na 0? Czy wystarczyłoby następujące?

myStruct _m1 = {0};

lub Czy musiałbym jawnie ustawić każdego członka na 0?

myStruct _m2 = {0,0};
Daan Timmer
źródło

Odpowiedzi:

143

Pierwszy jest najłatwiejszy ( wymaga mniej wpisywania ) i gwarantuje działanie, wszyscy członkowie będą mieli ustawioną wartość 0[Ref 1] .
Drugi jest bardziej czytelny.

Wybór zależy od preferencji użytkownika lub tego, który określa Twój standard kodowania.

[Odn. 1] Odniesienie do normy C99 6.7.8.21:

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ć inicjowane niejawnie tak samo jak obiekty, które mają statyczny czas trwania.

Dobry odczyt:
C i C ++: Częściowa inicjalizacja struktury automatycznej

Alok Save
źródło
9
Również używam = {};Jednak nie jestem pewien, czy jest to ważne.
William Entriken
15
@FullDecent puste nawiasy klamrowe do inicjalizacji to rozszerzenie GNU.
a3f
2
@ alias65536 Pytanie jest oznaczone jako C, a nie C ++.
a3f
3
Wystąpił błąd: „brak nawiasów klamrowych wokół inicjatora [-Werror = brakujące nawiasy klamrowe]” prawdopodobnie z powodu tablicy
składowej
3
@Edenia. Nie zgadzam się. Wiem już, co foo = {0}to znaczy. Gdybym zobaczył foo = ZERO_FULL, musiałbym grepować definicję ZERO_FULL.
Andrew Bainbridge,
32

Jeśli dane są zmienną statyczną lub globalną, są domyślnie wypełnione zerami, więc po prostu je zadeklaruj myStruct _m;

Jeśli dane są lokalną zmienną lub strefą przydzieloną na stertę, wyczyść je za pomocą memset:

memset(&m, 0, sizeof(myStruct));

Obecne kompilatory (np. Najnowsze wersje gcc) optymalizują to całkiem dobrze w praktyce. Działa to tylko wtedy, gdy wszystkie wartości zerowe (w tym wskaźniki null i zero zmiennoprzecinkowe) są reprezentowane jako wszystkie bity zerowe, co jest prawdą na wszystkich platformach, o których wiem (ale C standard zezwala na implementacje, w których jest to fałszywe; nie znam takiej implementacji) .

Możesz być może zakodować myStruct m = {};lub myStruct m = {0};(nawet jeśli pierwszy element członkowski myStructnie jest skalarem).

Mam wrażenie, że użycie memsetdla struktur lokalnych jest najlepsze i lepiej oddaje fakt, że w czasie wykonywania coś musi być zrobione (podczas gdy zwykle dane globalne i statyczne można rozumieć jako inicjowane w czasie kompilacji, bez żadnych kosztów w czasie wykonywania) .

Basile Starynkevitch
źródło
7
Nie ma gwarancji, że ustawienie wszystkich bajtów struktury na 0będzie równoważne z zainicjowaniem wszystkich elementów członkowskich struktury za pomocą 0jednak. Na wielu platformach będzie to prawda, ale nie powszechnie.
Sander De Dycker
1
Czy możesz podzielić się przykładem, Sander? Prawdziwa ciekawość. (Oczywiście, nie uniwersalnie prawda, niekoniecznie oznacza, że ​​istnieje łatwy do wyjaśnienia wyjątek, ale jeśli jest ...)
Steven Fisher
2
Standard C zezwala, aby wskaźnik zerowy (lub zerowa liczba zmiennoprzecinkowa) był reprezentowany w pamięci przez coś innego niż wszystkie bity zerowe. Robi to bardzo niewiele i dziwnych implementacji (nie mogę wymienić żadnej).
Basile Starynkevitch
-1, może się okazać, że inicjalizacja, o którą prosi OP, jest brzydka, ale jest to dokładnie to, co przewiduje standard i może być łatwo zoptymalizowane przez wszystkie kompilatory. Wtedy formularz {}nie jest prawidłowy w C, ale jest dostępny tylko w C ++.
Jens Gustedt
7
@Steven: Myślę tylko o niejasnych i / lub starych platformach. C FAQ zawiera listę platform, które miały NULLwskaźnik, który nie był tylko 0bitowy: c-faq.com/null/machexamp.html . Istnieje możliwość, że platforma nie używa IEEE 754 do reprezentowania wartości zmiennoprzecinkowych, ale używa innej reprezentacji, która nie ma wartości wszystkich 0bitów 0.0- ale wprawdzie nie znam takiej platformy.
Sander De Dycker
19

Patrz §6.7.9 Inicjalizacja:

21 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 zainicjowania tablicy o znanym rozmiarze niż elementów w tablicy, pozostała część agregacji powinny być inicjowane niejawnie tak samo jak obiekty, które mają statyczny czas trwania.

Więc tak, oba działają. Zauważ, że w C99 można również zastosować nowy sposób inicjalizacji, zwany inicjalizacją wyznaczoną:

myStruct _m1 = {.c2 = 0, .c1 = 1};
dirkgently
źródło
Przede wszystkim jest to już C89: open-std.org/JTC1/SC22/WG14/www/docs/n1124.pdf#page=139 (Ważne dla określonych celów przetwarzania sygnału)
Tobias