Namespaces
Variants

Objects and alignment

From cppreference.net

C-Programme erstellen, zerstören, greifen auf Objekte zu und manipulieren diese.

Ein Objekt in C ist ein Bereich von Datenspeicher in der Ausführungsumgebung, dessen Inhalt Werte repräsentieren kann (ein Wert ist die Bedeutung des Inhalts eines Objekts, wenn dieser als ein spezifischer Typ interpretiert wird).

Jedes Objekt hat

  • Größe (kann mit sizeof bestimmt werden)
  • Ausrichtungsanforderung (kann durch _Alignof (bis C23) alignof (seit C23) bestimmt werden) (seit C11)
  • Speicherdauer (automatisch, statisch, allokiert, thread-lokal)
  • Lebensdauer (gleich der Speicherdauer oder temporär)
  • Effektiver Typ (siehe unten)
  • Wert (der unbestimmt sein kann)
  • Optional ein Bezeichner , der dieses Objekt bezeichnet.

Objekte werden erstellt durch Deklarationen , Allokationsfunktionen , String-Literale , Verbundliterale , und durch Nicht-Lvalue-Ausdrücke, die Strukturen oder Unions mit Array-Mitgliedern zurückgeben.

Inhaltsverzeichnis

Objektdarstellung

Mit Ausnahme von Bitfeldern bestehen Objekte aus zusammenhängenden Sequenzen von einem oder mehreren Bytes, die jeweils aus CHAR_BIT Bits bestehen und können mit memcpy in ein Objekt vom Typ unsigned char [ n ] kopiert werden, wobei n die Größe des Objekts ist. Der Inhalt des resultierenden Arrays wird als Objektrepräsentation bezeichnet.

Wenn zwei Objekte die gleiche Objektdarstellung haben, vergleichen sie sich als gleich (außer wenn es sich um Gleitkomma-NaNs handelt). Die Umkehrung gilt nicht: Zwei Objekte, die sich als gleich vergleichen, können unterschiedliche Objektdarstellungen haben, da nicht jedes Bit der Objektdarstellung am Wert teilnehmen muss. Solche Bits können für Padding zur Erfüllung von Ausrichtungsanforderungen, für Paritätsprüfungen, zur Kennzeichnung von Trap Representations usw. verwendet werden.

Wenn eine Objektdarstellung keinen Wert des Objekttyps repräsentiert, wird dies als Trap-Darstellung bezeichnet. Der Zugriff auf eine Trap-Darstellung auf andere Weise als durch Lesen über einen Lvalue-Ausdruck vom Zeichentyp ist undefiniertes Verhalten. Der Wert einer Struktur oder Union ist niemals eine Trap-Darstellung, selbst wenn ein bestimmtes Mitglied eine solche ist.

Für Objekte vom Typ char , signed char und unsigned char ist jeder Bit der Objektdarstellung verpflichtet, an der Wertdarstellung teilzunehmen, und jedes mögliche Bitmuster repräsentiert einen eindeutigen Wert (keine Füllbits, Trap-Bits oder Mehrfachdarstellungen erlaubt).

Wenn Objekte von Ganzzahltypen ( short , int , long , long long ) mehrere Bytes belegen, ist die Verwendung dieser Bytes implementierungsdefiniert, aber die beiden vorherrschenden Implementierungen sind Big-Endian (POWER, Sparc, Itanium) und Little-Endian (x86, x86_64): Eine Big-Endian-Plattform speichert das höchstwertige Byte an der niedrigsten Adresse des Speicherbereichs, der von der Ganzzahl belegt wird, eine Little-Endian-Plattform speichert das niedrigstwertige Byte an der niedrigsten Adresse. Weitere Details finden Sie unter Endianness . Siehe auch Beispiel unten.

Obwohl die meisten Implementierungen keine Trap-Darstellungen, Padding-Bits oder Mehrfachdarstellungen für Integer-Typen erlauben, gibt es Ausnahmen; zum Beispiel kann ein Wert eines Integer-Typs auf Itanium eine Trap-Darstellung sein .

Effektiver Typ

Jedes Objekt hat einen effective type , der bestimmt, welche lvalue -Zugriffe gültig sind und welche gegen die strict aliasing rules verstoßen.

Wenn das Objekt durch eine Deklaration erstellt wurde, ist der deklarierte Typ dieses Objekts der effektive Typ des Objekts.

Wenn das Objekt durch eine Allokationsfunktion (einschließlich realloc ) erstellt wurde, hat es keinen deklarierten Typ. Ein solches Objekt erhält einen effektiven Typ wie folgt:

  • Der erste Schreibzugriff auf dieses Objekt durch einen L-Wert, der einen anderen Typ als den Zeichentyp hat, zu welchem Zeitpunkt der Typ dieses L-Wertes zum effektiven Typ dieses Objekts für diesen Schreibzugriff und alle nachfolgenden Lesezugriffe wird.
  • memcpy oder memmove kopieren ein anderes Objekt in dieses Objekt, oder kopieren ein anderes Objekt als ein Array von Zeichentyp in dieses Objekt, zu welchem Zeitpunkt der effektive Typ des Quellobjekts (falls vorhanden) zum effektiven Typ dieses Objekts für diesen Schreibzugriff und alle nachfolgenden Lesezugriffe wird.
  • Jeder andere Zugriff auf das Objekt ohne deklarierten Typ, der effektive Typ ist der Typ des für den Zugriff verwendeten L-Wertes.

Strict Aliasing

Gegeben ein Objekt mit effective type T1, ist die Verwendung eines Lvalue-Ausdrucks (typischerweise durch Dereferenzierung eines Zeigers) eines anderen Typs T2 undefiniertes Verhalten, es sei denn:

  • T2 und T1 sind kompatible Typen .
  • T2 ist eine cvr-qualifizierte Version eines Typs, der kompatibel mit T1 ist.
  • T2 ist eine vorzeichenbehaftete oder vorzeichenlose Version eines Typs, der kompatibel mit T1 ist.
  • T2 ist ein Aggregattyp oder Union-Typ, der einen der oben genannten Typen unter seinen Mitgliedern enthält (einschließlich, rekursiv, eines Mitglieds eines Subaggregats oder einer enthaltenen Union).
  • T2 ist ein Zeichentyp ( char , signed char , oder unsigned char ).
int i = 7;
char* pc = (char*)(&i);
if (pc[0] == '\x7') // Aliasing über char ist erlaubt
    puts("Dieses System verwendet Little-Endian");
else
    puts("Dieses System verwendet Big-Endian");
float* pf = (float*)(&i);
float d = *pf; // UB: float lvalue *p kann nicht für Zugriff auf int verwendet werden

Diese Regeln steuern, ob beim Kompilieren einer Funktion, die zwei Zeiger empfängt, der Compiler Code erzeugen muss, der einen Zeiger erneut liest, nachdem durch einen anderen geschrieben wurde:

// int* und double* können nicht aliasen
void f1(int* pi, double* pd, double d)
{
    // das Lesen von *pi kann nur einmal, vor der Schleife erfolgen
    for (int i = 0; i < *pi; i++)
        *pd++ = d;
}
struct S { int a, b; };
// int* und struct S* können Aliase sein, da S ein Aggregattyp mit einem Member vom Typ int ist
void f2(int* pi, struct S* ps, struct S s)
{
    // Lesen von *pi muss nach jedem Schreiben über *ps erfolgen
    for (int i = 0; i < *pi; i++)
        *ps++ = s;
}

Beachten Sie, dass das restrict-Qualifizierer verwendet werden kann, um anzuzeigen, dass zwei Zeiger sich nicht überlappen, selbst wenn die obigen Regeln dies zulassen würden.

Beachten Sie, dass Type-Punning auch durch das inaktive Mitglied einer union durchgeführt werden kann.

Ausrichtung

Jeder vollständige Objekttyp besitzt eine Eigenschaft namens Ausrichtungsanforderung , die einen ganzzahligen Wert vom Typ size_t darstellt und die Anzahl Bytes zwischen aufeinanderfolgenden Adressen angibt, an denen Objekte dieses Typs allokiert werden können. Die gültigen Ausrichtungswerte sind nicht-negative ganzzahlige Zweierpotenzen.

Die Ausrichtungsanforderung eines Typs kann abgefragt werden mit _Alignof (bis C23) alignof (seit C23) .

(seit C11)

Um die Ausrichtungsanforderungen aller Mitglieder einer Struktur zu erfüllen, kann nach einigen ihrer Mitglieder Auffüllung eingefügt werden.

#include <stdalign.h>
#include <stdio.h>
// objects of struct S can be allocated at any address
// because both S.a and S.b can be allocated at any address
struct S
{
    char a; // size: 1, alignment: 1
    char b; // size: 1, alignment: 1
}; // size: 2, alignment: 1
// objects of struct X must be allocated at 4-byte boundaries
// because X.n must be allocated at 4-byte boundaries
// because int's alignment requirement is (usually) 4
struct X
{
    int n;  // size: 4, alignment: 4
    char c; // size: 1, alignment: 1
    // three bytes padding
}; // size: 8, alignment: 4
int main(void)
{
    printf("sizeof(struct S) = %zu\n", sizeof(struct S));
    printf("alignof(struct S) = %zu\n", alignof(struct S));
    printf("sizeof(struct X) = %zu\n", sizeof(struct X));
    printf("alignof(struct X) = %zu\n", alignof(struct X));
}

Mögliche Ausgabe:

sizeof(struct S) = 2
alignof(struct S) = 1
sizeof(struct X) = 8
alignof(struct X) = 4

Jeder Objekttyp legt seine Ausrichtungsanforderung für jedes Objekt dieses Typs fest. Die schwächste (kleinste) Ausrichtung ist die Ausrichtung der Typen char , signed char und unsigned char und beträgt 1 . Die strengste (größte) fundamentale Ausrichtung eines beliebigen Typs ist implementierungsdefiniert und entspricht der Ausrichtung von max_align_t (seit C11) .

Fundamentale Ausrichtungen werden für Objekte aller Arten von Speicherdauern unterstützt.

Wenn die Ausrichtung eines Objekts mittels _Alignof (bis C23) alignof (seit C23) strenger (größer) gemacht wird als max_align_t , hat es eine erweiterte Ausrichtungsanforderung . Ein Struct- oder Union-Typ, dessen Mitglied eine erweiterte Ausrichtung hat, ist ein überausgerichteter Typ . Es ist implementierungsdefiniert, ob überausgerichtete Typen unterstützt werden, und ihre Unterstützung kann in jeder Art von Speicherdauer unterschiedlich sein.

Wenn ein Struct- oder Union-Typ S kein Mitglied eines überausgerichteten Typs hat oder mit einem Ausrichtungsspezifizierer deklariert wurde, der eine erweiterte Ausrichtung angibt, hat S eine fundamentale Ausrichtung.

Die atomare Version jedes arithmetischen oder Zeiger -Typs hat eine fundamentale Ausrichtung.

(seit C11)

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
DR 445 C11 ein Typ könnte erweiterte Ausrichtung ohne _Alignas besitzen es muss fundamentale Ausrichtung besitzen

Referenzen

  • C17-Standard (ISO/IEC 9899:2018):
  • 3.15 Objekt (S. 5)
  • 6.2.6 Darstellungen von Typen (S. 33-35)
  • 6.2.8 Ausrichtung von Objekten (S. 36-37)
  • 6.5/6-7 Ausdrücke (S. 55-56)
  • C11-Standard (ISO/IEC 9899:2011):
  • 3.15 Objekt (S. 6)
  • 6.2.6 Darstellungen von Typen (S. 44-46)
  • 6.2.8 Ausrichtung von Objekten (S. 48-49)
  • 6.5/6-7 Ausdrücke (S. 77)
  • C99-Standard (ISO/IEC 9899:1999):
  • 3.2 Ausrichtung (S: 3)
  • 3.14 Objekt (S: 5)
  • 6.2.6 Darstellungen von Typen (S: 37-39)
  • 6.5/6-7 Ausdrücke (S: 67-68)
  • C89/C90 Standard (ISO/IEC 9899:1990):
  • 1.6 Definitionen von Begriffen

Siehe auch