Zoeken…


Opmerkingen

Zie ook Grootte van integratietypes .

Klasse typen

Met "klasse" bedoelen we een type dat is gedefinieerd met behulp van het trefwoord class of struct (maar niet enum struct of enum class ).

  • Zelfs een lege klasse neemt nog minstens één byte opslag in beslag; het zal daarom puur uit vulling bestaan. Dit zorgt ervoor dat als p naar een object van een lege klasse verwijst, p + 1 een verschillend adres is en naar een verschillend object verwijst. Het is echter mogelijk dat een lege klasse een grootte 0 heeft wanneer deze wordt gebruikt als een basisklasse. Zie lege basisoptimalisatie .

    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
    
  • De objectrepresentatie van een klasse type bevat de objectrepresentaties van de basisklasse en niet-statische lidtypen. Daarom bijvoorbeeld in de volgende klasse:

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

    er is een opeenvolgende reeks van sizeof(int) bytes binnen een S object, een subobject genaamd , die de waarde van x , en een ander subobject met sizeof(char*) bytes dat de waarde van y . De twee kunnen niet worden verweven.

  • Als een klasse type leden en / of basisklassen met types t1, t2,...tN , moet de grootte minstens sizeof(t1) + sizeof(t2) + ... + sizeof(tN) gegeven de voorgaande punten . Afhankelijk van de uitlijningsvereisten van de leden en basisklassen, kan de compiler worden gedwongen om opvulling in te voegen tussen subobjecten, of aan het begin of einde van het volledige object.

    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).
    
  • Als padding in een object wordt ingevoegd vanwege uitlijningsvereisten, is de grootte groter dan de som van de afmetingen van de leden en basisklassen. Met n byte-uitlijning is de grootte meestal de kleinste veelvoud van n die groter is dan de grootte van alle leden en basisklassen. Elk lid memN zal typisch op een adres dat een veelvoud van plaatsen alignof(memN) en n zal typisch het grootste alignof van alle leden alignof s. Vanwege dit, als een lid met een kleinere alignof wordt gevolgd door een lid met een grotere alignof , is er een mogelijkheid dat het laatste lid niet correct zal worden uitgelijnd als het direct na de eerstgenoemde wordt geplaatst. In dit geval zal een opvulling (ook bekend als een uitlijnelement ) tussen de twee elementen worden geplaatst, zodat het laatste element de gewenste uitlijning kan hebben. Omgekeerd, als een lid met een grotere alignof wordt gevolgd door een lid met een kleinere alignof , is meestal geen opvulling nodig. Dit proces wordt ook wel "verpakken" genoemd.
    Omdat klassen doorgaans de alignof van hun lid delen met de grootste alignof , worden klassen doorgaans uitgelijnd met de alignof van het grootste ingebouwde type dat ze direct of indirect bevatten.

    // 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
  • Als strikte uitlijning wordt geforceerd met alignas , wordt opvulling gebruikt om het type te dwingen om aan de opgegeven uitlijning te voldoen, zelfs wanneer het anders kleiner zou zijn. Met de onderstaande definitie hebben Chars<5> bijvoorbeeld drie (of mogelijk meer) opvulbytes aan het einde ingevoegd zodat de totale grootte 8 is. Het is niet mogelijk dat een klasse met een uitlijning van 4 een grootte heeft van 5 omdat het onmogelijk zou zijn om een array van die klasse te maken, dus de grootte moet worden "afgerond" op een veelvoud van 4 door opvulbytes in te voegen.

    // 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");
    
  • Als twee niet-statische leden van een klasse dezelfde toegangsspecificatie hebben , komt degene die later in de declaratieorde komt, gegarandeerd later in de objectrepresentatie. Maar als twee niet-statische leden verschillende toegangsspecificaties hebben, is hun relatieve volgorde binnen het object niet gespecificeerd.
  • Het is niet gespecificeerd in welke volgorde de basisklasse-subobjecten binnen een object verschijnen, of ze opeenvolgend voorkomen en of ze vóór, na of tussen lid-subobjecten verschijnen.

Rekenkundige typen

Smalle karaktertypen

Het type unsigned char gebruikt alle bits om een binair getal weer te geven. Daarom, bijvoorbeeld als unsigned char is 8 bits lang, dan is de 256 mogelijke bitpatronen van een char object representeren de 256 verschillende waarden {0, 1, ..., 255}. Het nummer 42 wordt gegarandeerd weergegeven door het bitpatroon 00101010 .

Het type met signed char heeft geen opvulbits, dat wil zeggen, als signed char 8 bits lang zijn, heeft het 8 bits capaciteit om een getal te vertegenwoordigen.

Merk op dat deze garanties niet van toepassing zijn op andere typen dan smalle karaktertypen.

Geheel getaltypen

De niet-ondertekende gehele getallen gebruiken een puur binair systeem, maar kunnen opvulbits bevatten. Het is bijvoorbeeld mogelijk (hoewel onwaarschijnlijk) dat unsigned int 64 bits lang is, maar alleen gehele getallen tussen 0 en 2 32 - 1 kan opslaan. De andere 32 bits zouden opvulbits zijn, waarnaar niet direct moet worden geschreven.

De getekende typen integer gebruiken een binair systeem met een tekenbit en mogelijk opvulbits. Waarden die behoren tot het gemeenschappelijke bereik van een type met geheel getal en het bijbehorende type zonder geheel getal hebben dezelfde weergave. Als bijvoorbeeld het bitpatroon 0001010010101011 van een unsigned short object de waarde 5291 vertegenwoordigt, vertegenwoordigt het ook de waarde 5291 wanneer het wordt geïnterpreteerd als een short object.

Het wordt door de implementatie bepaald of een twee-complement, één-complement of teken-grootteweergave wordt gebruikt, aangezien alle drie de systemen voldoen aan de eis in de vorige paragraaf.

Zwevende punttypen

De waardeweergave van drijvende komma types is door de implementatie bepaald. Meestal voldoen de float en double types aan IEEE 754 en zijn ze 32 en 64 bits lang (dus float zou bijvoorbeeld 23 bits precisie hebben die 8 exponentbits en 1 tekenbit zou volgen). De standaard garandeert echter niets. Zwevende punttypen hebben vaak "valrepresentaties", die fouten veroorzaken wanneer ze in berekeningen worden gebruikt.

arrays

Een arraytype heeft geen opvulling tussen de elementen. Daarom is een array met elementtype T slechts een opeenvolging van T objecten die in volgorde in het geheugen zijn opgemaakt.

Een multidimensionale array is een array met arrays en het bovenstaande is recursief van toepassing. Bijvoorbeeld als we de verklaring hebben

int a[5][3];

dan is a een array van 5 arrays van 3 int s. Daarom wordt a[0] , die bestaat uit de drie elementen a[0][0] , a[0][1] , a[0][2] , opgeslagen in het geheugen vóór a[1] , die bestaat van a[1][0] , a[1][1] en a[1][2] . Dit wordt rij-hoofdorder genoemd .



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow