Ricerca…


Osservazioni

Vedi anche Dimensione dei tipi interi .

Tipi di classe

Per "classe", intendiamo un tipo che è stato definito usando la parola chiave class o struct (ma non enum struct o enum class ).

  • Anche una classe vuota occupa ancora almeno un byte di spazio; consisterà quindi esclusivamente di imbottitura. Ciò garantisce che se p punta a un oggetto di una classe vuota, allora p + 1 è un indirizzo distinto e punta a un oggetto distinto. Tuttavia, è possibile che una classe vuota abbia una dimensione pari a 0 quando viene utilizzata come classe base. Vedi l' ottimizzazione di base vuota .

    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 rappresentazione dell'oggetto di un tipo di classe contiene le rappresentazioni di oggetti della classe base e dei tipi di membri non statici. Pertanto, ad esempio, nella seguente classe:

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

    c'è una sequenza consecutiva di sizeof(int) byte all'interno di un oggetto S , chiamato subobject, che contiene il valore di x , e un altro subobject con sizeof(char*) byte che contiene il valore di y . I due non possono essere intercalati.

  • Se un tipo di classe ha membri e / o classi base con tipi t1, t2,...tN , la dimensione deve essere almeno sizeof(t1) + sizeof(t2) + ... + sizeof(tN) dati i punti precedenti . Tuttavia, a seconda dei requisiti di allineamento dei membri e delle classi di base, il compilatore può essere costretto a inserire il padding tra i sottooggetti, o all'inizio o alla fine dell'oggetto completo.

    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).
    
  • Se il riempimento è inserito in un oggetto a causa dei requisiti di allineamento, la dimensione sarà maggiore della somma delle dimensioni dei membri e delle classi base. Con l'allineamento n byte, la dimensione sarà in genere il multiplo più piccolo di n che è più grande della dimensione di tutti i membri e le classi base. Ogni membro memN verrà tipicamente collocato in un indirizzo che è un multiplo di alignof(memN) , e n sarà tipicamente il più grande alignof di tutti gli alignof dei membri. A causa di ciò, se un membro con un alignof più alignof è seguito da un membro con un alignof più alignof , esiste la possibilità che quest'ultimo non sia allineato correttamente se posto immediatamente dopo il primo. In questo caso, il riempimento (noto anche come membro di allineamento ) verrà posizionato tra i due membri, in modo che quest'ultimo possa avere l'allineamento desiderato. Viceversa, se un membro con un alignof più alignof è seguito da un membro con un alignof più alignof , di solito non sarà necessario alcun riempimento. Questo processo è anche noto come "imballaggio".
    A causa delle classi che in genere condividono l' alignof del loro membro con l' alignof più grande, le classi saranno in genere allineate con l' alignof del tipo più grande incorporato che contengono direttamente o indirettamente.

    // 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
  • Se l'allineamento rigoroso viene forzato con gli alignas , verrà utilizzato il riempimento per forzare il tipo a soddisfare l'allineamento specificato, anche quando altrimenti sarebbe più piccolo. Ad esempio, con la definizione seguente, Chars<5> avrà tre (o forse più) byte di riempimento inseriti alla fine in modo che la sua dimensione totale sia 8. Non è possibile per una classe con un allineamento di 4 avere una dimensione di 5 perché sarebbe impossibile creare una matrice di quella classe, quindi la dimensione deve essere "arrotondata" a un multiplo di 4 inserendo i byte di riempimento.

    // 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");
    
  • Se due membri non statici di una classe hanno lo stesso identificatore di accesso , allora quello che viene dopo in ordine di dichiarazione è garantito per venire successivamente nella rappresentazione dell'oggetto. Ma se due membri non statici hanno identificatori di accesso diversi, il loro ordine relativo all'interno dell'oggetto non è specificato.
  • Non è specificato l'ordine in cui gli oggetti secondari della classe base vengono visualizzati all'interno di un oggetto, sia che si verifichino consecutivamente, sia se compaiono prima, dopo o tra sottooggetti membri.

Tipi aritmetici

Tipi di caratteri stretti

Il tipo di unsigned char utilizza tutti i bit per rappresentare un numero binario. Pertanto, ad esempio, se il unsigned char è lungo 8 bit, i 256 pattern di bit possibili di un oggetto char rappresentano i 256 diversi valori {0, 1, ..., 255}. Il numero 42 è garantito per essere rappresentato dal modello di bit 00101010 .

Il tipo di signed char non ha bit di riempimento, cioè, se il signed char è lungo 8 bit, allora ha 8 bit di capacità per rappresentare un numero.

Nota che queste garanzie non si applicano a tipi diversi dai tipi di caratteri stretti.

Tipi interi

I tipi interi senza segno usano un sistema binario puro, ma possono contenere bit di riempimento. Ad esempio, è possibile (anche se improbabile) che l' unsigned int abbia una lunghezza di 64 bit, ma sia in grado di memorizzare interi compresi tra 0 e 2 32 - 1, inclusi. Gli altri 32 bit sarebbero i bit di riempimento, che non dovrebbero essere scritti direttamente.

I tipi interi con segno usano un sistema binario con un bit di segno ed eventualmente dei bit di riempimento. I valori che appartengono all'intervallo comune di un tipo di intero con segno e il tipo di intero senza segno corrispondente hanno la stessa rappresentazione. Ad esempio, se il modello di bit 0001010010101011 di un oggetto unsigned short rappresenta il valore 5291 , quindi rappresenta anche il valore 5291 quando viene interpretato come oggetto short .

È definito dall'implementazione se viene utilizzato il complemento a due, il complemento a un altro o la rappresentazione a livello di segno, poiché tutti e tre i sistemi soddisfano i requisiti del paragrafo precedente.

Tipi di virgola mobile

La rappresentazione del valore dei tipi a virgola mobile è definita dall'implementazione. Più comunemente, i tipi float e double sono conformi a IEEE 754 e sono lunghi 32 e 64 bit (quindi, ad esempio, float avrebbe 23 bit di precisione che seguiranno 8 bit esponenziali e 1 bit di segno). Tuttavia, lo standard non garantisce nulla. I tipi a virgola mobile hanno spesso "rappresentazioni di trap", che causano errori quando vengono utilizzati nei calcoli.

Array

Un tipo di array non ha padding tra i suoi elementi. Pertanto, una matrice con elemento di tipo T è solo una sequenza di oggetti T disposti in memoria, nell'ordine.

Una matrice multidimensionale è una matrice di matrici e la suddetta si applica in modo ricorsivo. Ad esempio, se abbiamo la dichiarazione

int a[5][3];

quindi a è una matrice di 5 matrici di 3 int s. Pertanto, a[0] , che consiste dei tre elementi a[0][0] , a[0][1] , a[0][2] , è disposto in memoria prima di a[1] , che consiste di a[1][0] , a[1][1] e a[1][2] . Questo è chiamato ordine principale di riga .



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow