2016-06-05 6 views
14

Wenn ein C-Compiler eine Struktur auffüllt, um die Felder an ihre native Ausrichtung auszurichten, und diese Struktur dann initialisiert wird, wird das Padding auf Null initialisiert?Initialisiert C Strukturauffüllung auf Null?

Zum Beispiel die folgende Struktur:

typedef struct foo_t_ { 
    int a; 
    char b; 
    int c; 
    char d; 
} foo_t; 

Auf vielen Systemen dieser (schlecht konzipiert) Struktur eine sizeof(foo_t) von 16, mit insgesamt 6 Bytes padding, 3 Bytes nach jedem der Zeichen haben würde.

Wenn wir die Struktur wie initialisieren:

foo_t foo = { .a = 1, .b = '2' }; 

dann die Felder foo.a-1 und foo.b gesetzt werden wird, um den Charakter festgelegt werden ‚2‘. Die nicht spezifizierten Felder (`foo.c 'und' foo.d ') werden automatisch auf 0 gesetzt. Die Frage ist, was passiert mit den 6 Bytes des Padding? Wird das auch automatisch auf 0 gesetzt? oder ist es undefiniertes Verhalten?

Der Anwendungsfall ist, dass ich Hashes von Datenstrukturen Berechnung werden:

foo_t foo = { .a = 1, .b = '2' }; 
foo_t bar = { .a = 1, .b = '2' }; 
uint32_t hash_foo = calc_hash(&foo, sizeof(foo)); 
uint32_t hash_bar = calc_hash(&bar, sizeof(bar)); 

und ich möchte sicher sein, dass hash_foo und hash_bar gleich sind. Ich könnte dies garantieren, indem ich zuerst memset() benutze, um die Strukturen zu löschen und sie dann zu initialisieren, aber es scheint sauberer zu sein, stattdessen C-Initialisierung zu verwenden.

In der Praxis, GCC auf meinem System löscht auch die Auffüllung, aber ich weiß nicht, ob das garantiert ist.

+3

Wäre die Referenz auf diesen Speicher in keinem Fall UB? –

+1

Warum machen Sie den Hash nicht zu einer Funktion der tatsächlichen Strukturelemente ohne Abhängigkeit von der Auffüllung? –

+0

Beziehen Sie sich in Ihrem Beispiel auf einen Fall, in dem die Variable lokal in einer Funktion oder global deklariert wird? –

Antwort

14

Im Allgemeinen, wie pro C11, für jede uninitialized Objekt Kapitel §6.2.6.1/6,

Wenn ein Wert in einem Objekt der Struktur oder Vereinigung Typ gespeichert ist, in einem Element mit Objekt, die Bytes der Objektrepräsentation, die jedem Füllzeichen entsprechen, nehmen nicht spezifizierte Werte.

Wenn aber die Teil Initialisierung durchgeführt wird, in diesem Fall für Rest der Mitglieder, geschieht die Initialisierungsparameter, als ob ein Objekt, das statisch oder Fadenspeicherdauer hat, dann unter Angabe der gleichen Standard Kapitel §6.7.9/21

Wenn weniger Initialisierungen in einer spange beigefügte Liste sind, als es Elemente oder Elemente ein Aggregats oder weniger Zeichen in einer Zeichenkette literal verwendeten eine Reihe von bekannten zu initialisieren Größe als es Elemente im Array sind, die rem Ainder des Aggregats soll implizit genauso initialisiert werden wie Objekte mit statischer Speicherdauer.

und in Bezug auf die implizite Initialisierung von Objekten mit statischer Speicherdauer Absatz 10

Wenn ein Objekt, das statisch oder Fadenspeicherdauer hat, wird explizit nicht initialisiert ist, dann:

  • Wenn es ein Aggregat ist, wird jedes Mitglied gemäß diesen Regeln (rekursiv) initialisiert ( ) und jedes Padding wird auf Null Bits initialisiert;

Also, in Ihrem Fall, Polsterung für die übrigen Objekte sind garantiert 0 sein, aber nicht für die Mitglieder, die die initializers erhalten hat.

Also, über alles, sollten Sie nicht auf eine implizite Initialisierung von 0, verwenden Sie memset().

Das gesagt wird, in jedem Fall ist es nicht empfohlen (erforderlich), abhängig von Füll-Bytes, falls vorhanden. Verwenden Sie die exakten Mitgliedsvariablen und berechnen Sie den Hash basierend auf diesen Werten.

+0

'memset' setzt nur Bytes, aber nicht alle Typen haben eine "all-bits zero" Kodierung für den Wert "0". Gleitkommaarten und Zeiger (_null pointer_) - "memset" sind in solchen Fällen ziemlich nutzlos. Auch der zweite Teil (bitte fügen Sie Absatzzahlen hinzu!).) ist über Padding ** Bits ** in den Mitgliedern selbst, nicht padding Bytes zwischen den Mitgliedern des aggregate (dh "struct", Arrays haben keine Auffüllung zwischen Objekten). – Olaf

+0

@Olaf Sir, danke fo r der Kommentar, ich habe die Antwort mit Kapiteln angehängt.In Bezug auf die Nullstellencodierung und -auffüllung zwischen Array-Mitgliedern stimme ich Ihnen zu, aber in diesem Fall sind nur die Füllbits anwendbar, nicht wahr? –

+0

Ich denke OP fragt nach den Füll-Bytes zwischen den Mitgliedern, nicht die Bits in jedem Mitglied. Aber ich werde auch einen Kommentar auf die Frage hinterlassen. – Olaf