Können C-Arrays Padding zwischen Elementen enthalten?

Lesezeit: 6 Minuten

Benutzer-Avatar
EM

Ich habe ein Gerücht gehört, dass in C Arrays, die in Strukturen enthalten sind, möglicherweise eine Auffüllung zwischen den Elementen des Arrays haben. Offensichtlich kann die Füllmenge zwischen keinem Elementpaar variieren, oder die Berechnung des nächsten Elements in einem Array ist mit einfacher Zeigerarithmetik nicht möglich.

Dieses Gerücht besagte auch, dass Arrays, die nicht in Strukturen enthalten sind, garantiert kein Padding enthalten. Ich weiß zumindest, dass dieser Teil wahr ist.

Also, im Code lautet das Gerücht:

{
    // Given this:
    struct { int values[20]; } foo;
    int values[20];

    // This may be true:
    sizeof(values) != sizeof(foo.values);
}

Da bin ich mir ziemlich sicher sizeof(values) wird immer gleich sein sizeof(foo.values). Ich konnte jedoch im C-Standard (insbesondere C99) nichts finden, was dies ausdrücklich bestätigt oder dementiert.

Weiß jemand, ob dieses Gerücht in irgendeinem C-Standard angesprochen wird?

bearbeiten: Ich verstehe, dass es möglicherweise eine Auffüllung zwischen dem Ende des Arrays gibt foo.values und das Ende der Struktur foo und dass der Standard besagt, dass es keine Auffüllung zwischen dem Start von geben wird foo und Beginn von foo.values. Hat aber jemand eine Zitat aus oder Bezug auf der Standard, wo es heißt, es gibt keine Polsterung zwischen den Elementen von foo.values?

  • Ich habe keine Referenzen dafür, aber ich bin mir ziemlich sicher, dass ich gelesen habe, dass der Compiler Strukturen nach Belieben ausrichten kann. Im Allgemeinen wird dies wahrscheinlich in der Weise geschehen, die Cletus beschreibt.

    – Emil H

    30. Juni 2009 um 23:59 Uhr

  • scheint eine Menge Leute zu vermissen, dass der Vergleich zwischen den beiden Arrays und nicht zwischen Array/Struktur erfolgt. sizeof(Werte) != sizeof(foo); das ist nicht was er tut, aber was die Leute in einigen Antworten zu denken scheinen

    – Joakim Elofsson

    1. Juli 2009 um 0:18 Uhr

Benutzer-Avatar
Chris Argin

Nein, zwischen den Elementen eines Arrays wird niemals aufgefüllt. Das ist ausdrücklich nicht erlaubt. Der C99-Standard nennt Array-Typen “Ein Array-Typ beschreibt eine zusammenhängend zugewiesene, nicht leere Menge von Objekten …”. Im Gegensatz dazu wird eine Struktur “sequenziell”, nicht “zusammenhängend” zugewiesen.

Innerhalb einer Struktur kann vor oder nach einem Array aufgefüllt werden; das ist ein ganz anderes Tier. Der Compiler könnte das tun, um die Ausrichtung der Struktur zu unterstützen, aber der C-Standard sagt nichts darüber aus.

  • Kommt darauf an, was du meinst. Ein Compiler kann am Ende der Struktur Padding hinzufügen (siehe mein Beispiel). Wenn Sie eine solche Struktur nehmen und daraus ein Array erstellen, gibt es unbenutzte Bytes zwischen den verwendeten Bytes, aber jedes Element des Arrays ist immer sizeof(T) Bytes nach dem vorherigen. Aber sizeof(Ta) + sizeof(Tb) + … darf nicht gleich sizeof(T) sein.

    – Thanatos

    1. Juli 2009 um 0:08 Uhr

  • “Die Größe des Vergleichs, den Sie anstellen, könnte das abholen” Nein? compair liegt zwischen den beiden Arrays, nicht zwischen Array und Struct

    – Joakim Elofsson

    1. Juli 2009 um 0:09 Uhr

  • @Thanatos – Ich stimme grundsätzlich zu, außer dass, wenn der Compiler Bytes am Ende der Struktur hinzufügt, dies in der Größe von enthalten ist. Sizeof befindet sich auf einem Typ, nicht auf einer Instanz dieses Typs, und der Typ weiß nicht, ob er in einem Array verwendet wird oder nicht.

    – Chris Arguin

    1. Juli 2009 um 0:22 Uhr

  • Danke für das Zitat. Es stammt aus Abschnitt 6.2.5 Absatz 20 für alle, die daran interessiert sind, es nachzuschlagen.

    – EM

    1. Juli 2009 um 0:24 Uhr

Vorsicht hier. Padding kann am Ende der Struktur hinzugefügt werden, wird jedoch nicht zwischen den Elementen des Arrays hinzugefügt, wie Sie in Ihrer Frage angeben. Arrays verweisen immer auf zusammenhängenden Speicher, obwohl bei einem Array von Strukturen jedem Element als Teil der Struktur selbst Auffüllungen hinzugefügt werden können.

In Ihrem Beispiel ist die values und foo.values Arrays haben die gleiche Größe. Jede Polsterung wird Teil der Struktur sein foo stattdessen.

Hier ist die Erklärung dazu warum Eine Struktur muss möglicherweise zwischen ihren Mitgliedern oder sogar nach ihrem letzten Mitglied aufgefüllt werden, und warum ein Array dies nicht tut:

Unterschiedliche Typen können unterschiedliche Ausrichtungsanforderungen haben. Einige Typen müssen an Wortgrenzen ausgerichtet werden, andere an doppelten oder sogar vierfachen Wortgrenzen. Um dies zu erreichen, kann eine Struktur Füllbytes zwischen ihren Mitgliedern enthalten. Nachfolgende Füllbytes könnten erforderlich sein, da die Speicherstelle direkt hinter einer Struktur auch den Ausrichtungsanforderungen der Struktur entsprechen muss, dh wenn bar ist vom Typ struct foo *dann

(struct foo *)((char *)bar + sizeof(struct foo))

liefert einen gültigen Zeiger auf struct foo (dh fällt nicht aufgrund einer Fehlausrichtung aus).

Da jedes ‘Mitglied’ eines Arrays die gleiche Ausrichtungsanforderung hat, gibt es keinen Grund, Padding einzuführen. Dies gilt auch für Arrays, die in Strukturen enthalten sind: Wenn das erste Element eines Arrays korrekt ausgerichtet ist, sind es auch alle folgenden Elemente.

Benutzer-Avatar
Thanatos

Mehr oder weniger. Variablen werden abhängig von der Variablen häufig an einer bestimmten Grenze ausgerichtet. Nehmen Sie zum Beispiel Folgendes:

typedef struct
{
    double d;
    char c;
} a_type_t;

double und char sind 8 bzw. 1 Byte auf meinem System. Insgesamt 9. Diese Struktur wird jedoch 16 Byte umfassen, sodass die Doubles immer 8-Byte-ausgerichtet sind. Wenn ich nur ints, chars usw. verwendet hätte, könnte die Ausrichtung 1, 2, 4 oder 8 sein.

Für einige Typ T, sizeof(T) kann oder kann nicht gleich sein sizeof(T.a) + sizeof(T.b) + sizeof(T.c) ... usw.

Im Allgemeinen ist dies vollständig vom Compiler und der Architektur abhängig. In der Praxis spielt es nie eine Rolle.

Benutzer-Avatar
Cletus

In Betracht ziehen:

struct {
  short s;
  int i;
} s;

Unter der Annahme, dass Shorts 16 Bit haben und Sie 32 Bit verwenden, wird die Größe dies tun wahrscheinlich 8 Bytes sein, da jedes Strukturmitglied dazu neigt, an einer Wortgrenze (in diesem Fall 32 Bit) ausgerichtet zu sein. Ich sage “wahrscheinlich”, weil es sich um ein implementierungsspezifisches Verhalten handelt, das durch Compiler-Flags und dergleichen variiert werden kann.

Es sollte betont werden, dass dies ein Implementierungsverhalten ist, das nicht unbedingt durch den C-Standard definiert ist. Ähnlich wie die Größe von Shorts, Ints und Longs (der C-Standard besagt einfach, dass Shorts nicht größer als Ints und Longs nicht kleiner als Ints sind, was als 16/32/32, 16/32/64 enden kann , 32/32/64 oder eine Reihe anderer Konfigurationen).

  • In ARM-basierten Maschinen wird es ausreichen, aber es ist auch sehr gefährlich, da ARM keine Ausrichtungsprüfungen durchführt

    – Ignas Limanauskas

    30. Juni 2009 um 23:59 Uhr

  • Eigentlich glaube ich, dass auf x86- und amd64-Rechnern, die eine Größe von 6 haben, für gcc-Compiler kein Vorteil darin besteht, dass ein Zeichen auf 8 Byte ausgerichtet ist. Aber wie Sie bereits erwähnt haben, ist dies Compiler-abhängig.

    – Thanatos

    1. Juli 2009 um 0:04 Uhr

  • Die Größe ist 8 auf x86- und amd64-Rechnern mit gcc. Ich stimme zu, dass dies Compiler-abhängig ist; Im Beispiel in dieser Antwort geht es um die natürliche Ausrichtung eines int.

    – Jam

    21. Februar 2010 um 8:53 Uhr

  • In ARM-basierten Maschinen wird es ausreichen, aber es ist auch sehr gefährlich, da ARM keine Ausrichtungsprüfungen durchführt

    – Ignas Limanauskas

    30. Juni 2009 um 23:59 Uhr

  • Eigentlich glaube ich, dass auf x86- und amd64-Rechnern, die eine Größe von 6 haben, für gcc-Compiler kein Vorteil darin besteht, dass ein Zeichen auf 8 Byte ausgerichtet ist. Aber wie Sie bereits erwähnt haben, ist dies Compiler-abhängig.

    – Thanatos

    1. Juli 2009 um 0:04 Uhr

  • Die Größe ist 8 auf x86- und amd64-Rechnern mit gcc. Ich stimme zu, dass dies Compiler-abhängig ist; Im Beispiel in dieser Antwort geht es um die natürliche Ausrichtung eines int.

    – Jam

    21. Februar 2010 um 8:53 Uhr

1382820cookie-checkKönnen C-Arrays Padding zwischen Elementen enthalten?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy