Recherche…


Remarques

Voir aussi Taille des types intégraux .

Types de classes

Par «classe», nous entendons un type défini avec le mot struct clé class ou struct (mais pas enum struct ou enum class ).

  • Même une classe vide occupe au moins un octet de stockage; il s'agira donc uniquement de rembourrage. Cela garantit que si p pointe sur un objet d'une classe vide, alors p + 1 est une adresse distincte et pointe vers un objet distinct. Cependant, il est possible qu'une classe vide ait une taille de 0 lorsqu'elle est utilisée comme classe de base. Voir optimisation de base vide .

    class Empty_1 {};                               // sizeof(Empty_1)       == 1
    class Empty_2 {};                               // sizeof(Empty_2)       == 1
    class Derived : Empty_1 {};                     // sizeof(Derived)       == 1
    class DoubleDerived : Empty_1, Empty_2 {};      // sizeof(DoubleDerived) == 1
    class Holder { Empty_1 e; };                    // sizeof(Holder)        == 1
    class DoubleHolder { Empty_1 e1; Empty_2 e2; }; // sizeof(DoubleHolder)  == 2
    class DerivedHolder : Empty_1 { Empty_1 e; };   // sizeof(DerivedHolder) == 2
    
  • La représentation d'objet d'un type de classe contient les représentations d'objet de la classe de base et des types de membres non statiques. Par exemple, dans la classe suivante:

    struct S {
        int x;
        char* y;
    };
    

    il existe une séquence consécutive de sizeof(int) octets sizeof(int) dans un objet S , appelée sous - objet, qui contient la valeur de x , et un autre sous-objet de sizeof(char*) octets sizeof(char*) contenant la valeur de y . Les deux ne peuvent pas être entrelacés.

  • Si un type de classe a des membres et / ou des classes de base avec les types t1, t2,...tN , la taille doit être au minimum sizeof(t1) + sizeof(t2) + ... + sizeof(tN) compte tenu des points précédents . Toutefois, en fonction des exigences d' alignement des membres et des classes de base, le compilateur peut être contraint d'insérer un remplissage entre les sous-objets ou au début ou à la fin de l'objet complet.

    struct AnInt      { int i; };
      // sizeof(AnInt)        == sizeof(int)
      // Assuming a typical 32- or 64-bit system, sizeof(AnInt)        == 4 (4).
    struct TwoInts    { int i, j; };
      // sizeof(TwoInts)      >= 2 * sizeof(int)
      // Assuming a typical 32- or 64-bit system, sizeof(TwoInts)      == 8 (4 + 4).
    struct IntAndChar { int i; char c; };
      // sizeof(IntAndChar)   >= sizeof(int) + sizeof(char)
      // Assuming a typical 32- or 64-bit system, sizeof(IntAndChar)   == 8 (4 + 1 + padding).
    struct AnIntDerived : AnInt { long long l; };
      // sizeof(AnIntDerived) >= sizeof(AnInt) + sizeof(long long)
      // Assuming a typical 32- or 64-bit system, sizeof(AnIntDerived) == 16 (4 + padding + 8).
    
  • Si le remplissage est inséré dans un objet en raison des exigences d'alignement, la taille sera supérieure à la somme des tailles des membres et des classes de base. Avec l'alignement sur n octets, la taille sera généralement le plus petit multiple de n supérieur à la taille de tous les membres et classes de base. Chaque membre memN sera généralement placé à une adresse multiple de alignof(memN) , et n sera généralement le plus grand alignof de tous les alignof des membres. De ce fait, si un membre avec un alignof plus alignof est suivi par un membre avec un alignof plus alignof , il est possible que ce dernier membre ne soit pas correctement aligné s'il est placé immédiatement après le premier. Dans ce cas, un rembourrage (également appelé élément d'alignement ) sera placé entre les deux éléments, de sorte que ce dernier membre puisse avoir son alignement souhaité. Inversement, si un membre avec un alignof plus alignof est suivi par un membre avec un alignof plus alignof , aucun remplissage ne sera généralement nécessaire. Ce processus est également appelé "emballage".
    Étant donné que les classes partageant généralement l' alignof de leur membre avec l' alignof le plus alignof , les classes seront généralement alignées sur l' alignof du plus grand type intégré qu'elles contiennent directement ou indirectement.

    // Assume sizeof(short) == 2, sizeof(int) == 4, and sizeof(long long) == 8.
    // Assume 4-byte alignment is specified to the compiler.
    struct Char { char c; };
      // sizeof(Char)                == 1 (sizeof(char))
    struct Int  { int i; };
      // sizeof(Int)                 == 4 (sizeof(int))
    struct CharInt { char c; int i; };
      // sizeof(CharInt)             == 8 (1 (char) + 3 (padding) + 4 (int))
    struct ShortIntCharInt { short s; int i; char c; int j; };
      // sizeof(ShortIntCharInt)     == 16 (2 (short) + 2 (padding) + 4 (int) + 1 (char) +
      //                                    3 (padding) + 4 (int))
    struct ShortIntCharCharInt { short s; int i; char c; char d; int j; };
      // sizeof(ShortIntCharCharInt) == 16 (2 (short) + 2 (padding) + 4 (int) + 1 (char) +
      //                                    1 (char) + 2 (padding) + 4 (int))
    struct ShortCharShortInt { short s; char c; short t; int i; };
      // sizeof(ShortCharShortInt)   == 12 (2 (short) + 1 (char) + 1 (padding) + 2 (short) +
      //                                    2 (padding) + 4 (int))
    struct IntLLInt { int i; long long l; int j; };
      // sizeof(IntLLInt)            == 16 (4 (int) + 8 (long long) + 4 (int))
      // If packing isn't explicitly specified, most compilers will pack this as
      //   8-byte alignment, such that:
      // sizeof(IntLLInt)            == 24 (4 (int) + 4 (padding) + 8 (long long) +
      //                                    4 (int) + 4 (padding))
    
    // Assume sizeof(bool) == 1, sizeof(ShortIntCharInt) == 16, and sizeof(IntLLInt) == 24.
    // Assume default alignment: alignof(ShortIntCharInt) == 4, alignof(IntLLInt) == 8.
    struct ShortChar3ArrShortInt {
        short s;
        char c3[3];
        short t;
        int i;
    };
      // ShortChar3ArrShortInt has 4-byte alignment: alignof(int) >= alignof(char) &&
      //                                             alignof(int) >= alignof(short)
      // sizeof(ShortChar3ArrShortInt) == 12 (2 (short) + 3 (char[3]) + 1 (padding) +
      //                                      2 (short) + 4 (int))
      // Note that t is placed at alignment of 2, not 4.  alignof(short) == 2.
    
    struct Large_1 {
        ShortIntCharInt sici;
        bool b;
        ShortIntCharInt tjdj;
    };
      // Large_1 has 4-byte alignment.
        // alignof(ShortIntCharInt) == alignof(int) == 4
        // alignof(b) == 1
        // Therefore, alignof(Large_1) == 4.
      // sizeof(Large_1) == 36 (16 (ShortIntCharInt) + 1 (bool) + 3 (padding) +
      //                        16 (ShortIntCharInt))
    struct Large_2 {
        IntLLInt illi;
        float f;
        IntLLInt jmmj;
    };
      // Large_2 has 8-byte alignment.
        // alignof(IntLLInt) == alignof(long long) == 8
        // alignof(float) == 4
        // Therefore, alignof(Large_2) == 8.
      // sizeof(Large_2) == 56 (24 (IntLLInt) + 4 (float) + 4 (padding) + 24 (IntLLInt))
    
C ++ 11
  • Si l'alignement strict est forcé avec alignas , le remplissage sera utilisé pour forcer le type à respecter l'alignement spécifié, même s'il serait autrement plus petit. Par exemple, avec la définition ci-dessous, les caractères Chars<5> auront trois (ou peut-être plus) octets de remplissage insérés à la fin de sorte que leur taille totale soit 8. Il n'est pas possible pour une classe avec un alignement de 4 d'avoir une taille de 5 car il serait impossible de faire un tableau de cette classe, donc la taille doit être "arrondie" à un multiple de 4 en insérant des octets de remplissage.

    // This type shall always be aligned to a multiple of 4.  Padding shall be inserted as
    // needed.
    // Chars<1>..Chars<4> are 4 bytes, Chars<5>..Chars<8> are 8 bytes, etc.
    template<size_t SZ>
    struct alignas(4) Chars { char arr[SZ]; };
    
    static_assert(sizeof(Chars<1>) == sizeof(Chars<4>), "Alignment is strict.\n");
    
  • Si deux membres non statiques d'une classe ont le même spécificateur d'accès , celui qui apparaîtra plus tard dans l'ordre de déclaration sera garanti plus tard dans la représentation de l'objet. Mais si deux membres non statiques ont des spécificateurs d'accès différents, leur ordre relatif dans l'objet n'est pas spécifié.
  • Il n'est pas spécifié dans quel ordre les sous-objets de classe de base apparaissent dans un objet, qu'ils soient consécutifs ou non, qu'ils apparaissent avant, après ou entre les sous-objets membres.

Types arithmétiques

Types de caractères étroits

Le type de caractère unsigned char utilise tous les bits pour représenter un nombre binaire. Par conséquent, par exemple, si le caractère unsigned char longueur de 8 bits, alors les 256 modèles de bits possibles d'un objet char représentent les 256 valeurs différentes {0, 1, ..., 255}. Le nombre 42 est garanti pour être représenté par le modèle de bit 00101010 .

Le type de caractère signed char n'a pas de bits de remplissage, c'est -à- dire que si le caractère signed char longueur de 8 bits, il a une capacité de 8 bits pour représenter un nombre.

Notez que ces garanties ne s'appliquent pas aux types autres que les types de caractères étroits.

Types entiers

Les types entiers non signés utilisent un système binaire pur, mais peuvent contenir des bits de remplissage. Par exemple, il est possible (mais improbable) que unsigned int ait une longueur de 64 bits, mais soit uniquement capable de stocker des entiers compris entre 0 et 2 32 - 1 inclus. Les 32 autres bits seraient des bits de remplissage, auxquels il ne faut pas écrire directement.

Les types entiers signés utilisent un système binaire avec un bit de signe et éventuellement des bits de remplissage. Les valeurs qui appartiennent à la plage commune d'un type d'entier signé et au type d'entier non signé correspondant ont la même représentation. Par exemple, si le modèle de bit 0001010010101011 d'un objet unsigned short représente la valeur 5291 , il représente également la valeur 5291 lorsqu'il est interprété comme un objet short .

Il est défini par la mise en œuvre si une représentation à deux, un complément ou une magnitude de signe est utilisée, car les trois systèmes satisfont aux exigences du paragraphe précédent.

Virgule flottante

La représentation de la valeur des types à virgule flottante est définie par l'implémentation. Le plus souvent, les types float et double sont conformes à IEEE 754 et ont une longueur de 32 et 64 bits (par exemple, float aurait 23 bits de précision qui suivraient 8 bits d’exposant et 1 bit de signe). Cependant, la norme ne garantit rien. Les types à virgule flottante ont souvent des "représentations d'interruptions", qui provoquent des erreurs lorsqu'elles sont utilisées dans les calculs.

Tableaux

Un type de tableau n'a pas de remplissage entre ses éléments. Par conséquent, un tableau avec le type d'élément T n'est qu'une séquence d'objets T disposés en mémoire, dans l'ordre.

Un tableau multidimensionnel est un tableau de tableaux, et ce qui précède s'applique de manière récursive. Par exemple, si nous avons la déclaration

int a[5][3];

alors a est un tableau de 5 tableaux de 3 int s. Par conséquent, a[0] , qui consiste en trois éléments a[0][0] , a[0][1] , a[0][2] , est mis en mémoire avant a[1] , qui consiste à de a[1][0] , a[1][1] et a[1][2] . Ceci s'appelle ordre majeur de rangée .



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow