Buscar..


Observaciones

Ver también Tamaño de tipos integrales .

Tipos de clase

Por "clase", nos referimos a un tipo que se definió usando la palabra clave class o struct (pero no enum struct o enum class ).

  • Incluso una clase vacía aún ocupa al menos un byte de almacenamiento; Por lo tanto, consistirá puramente de relleno. Esto garantiza que si p apunta a un objeto de una clase vacía, p + 1 es una dirección distinta y apunta a un objeto distinto. Sin embargo, es posible que una clase vacía tenga un tamaño de 0 cuando se utiliza como clase base. Ver la optimización de la base vacía .

    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 representación de objeto de un tipo de clase contiene las representaciones de objeto de la clase base y los tipos de miembros no estáticos. Por lo tanto, por ejemplo, en la siguiente clase:

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

    hay una secuencia consecutiva de bytes de sizeof(int) dentro de un objeto S , llamado subobjeto, que contiene el valor de x , y otro subobjeto con bytes de sizeof(char*) que contiene el valor de y . Los dos no pueden ser intercalados.

  • Si un tipo de clase tiene miembros y / o clases base con los tipos t1, t2,...tN , el tamaño debe ser al menos sizeof(t1) + sizeof(t2) + ... + sizeof(tN) dados los puntos anteriores . Sin embargo, dependiendo de los requisitos de alineación de los miembros y las clases base, el compilador puede verse obligado a insertar relleno entre subobjetos, o al principio o al final del objeto 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).
    
  • Si el relleno se inserta en un objeto debido a los requisitos de alineación, el tamaño será mayor que la suma de los tamaños de los miembros y las clases base. Con la alineación de n bytes, el tamaño normalmente será el múltiplo más pequeño de n que es más grande que el tamaño de todos los miembros y clases base. Cada miembro memN normalmente se coloca en una dirección que es un múltiplo de alignof(memN) , y n será típicamente la más grande alignof de todos los miembros alignof s. Debido a esto, si un miembro con una menor alignof es seguido por un miembro con una mayor alignof , existe la posibilidad de que el último miembro no se alinee correctamente si se coloca inmediatamente después del anterior. En este caso, el relleno (también conocido como miembro de alineación ) se colocará entre los dos miembros, de modo que el último miembro pueda tener la alineación deseada. Por el contrario, si un miembro con una alignof más alignof es seguido por un miembro con una alignof más alignof , generalmente no será necesario alignof . Este proceso también se conoce como "embalaje".
    Debido a que las clases normalmente comparten la alignof de su miembro con la alignof más alignof , las clases típicamente se alinearán con la alignof del tipo integrado más grande que contengan directa o indirectamente.

    // 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 se fuerza una alineación estricta con las alineaciones, se alignas relleno para forzar al tipo a cumplir con la alineación especificada, incluso cuando de lo contrario sería más pequeño. Por ejemplo, con la definición a continuación, los caracteres Chars<5> tendrán tres (o posiblemente más) bytes de relleno insertados al final, de modo que su tamaño total sea 8. No es posible que una clase con una alineación de 4 tenga un tamaño. de 5 porque sería imposible hacer una matriz de esa clase, por lo que el tamaño debe "redondearse" a un múltiplo de 4 insertando bytes de relleno.

    // 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 dos miembros no estáticos de una clase tienen el mismo especificador de acceso , entonces se garantiza que el que viene más tarde en el orden de declaración vendrá más adelante en la representación del objeto. Pero si dos miembros no estáticos tienen diferentes especificadores de acceso, su orden relativo dentro del objeto no se especifica.
  • No se especifica en qué orden aparecen los subobjetos de la clase base dentro de un objeto, ya sea que aparezcan consecutivamente, y si aparecen antes, después o entre subobjetos miembros.

Tipos aritméticos

Tipos de caracteres estrechos

El tipo unsigned char utiliza todos los bits para representar un número binario. Por lo tanto, por ejemplo, si el unsigned char tiene una longitud de 8 bits, los 256 patrones de bits posibles de un objeto char representan los 256 valores diferentes {0, 1, ..., 255}. El número 42 está garantizado para ser representado por el patrón de bits 00101010 .

El tipo signed char no tiene bits de relleno, es decir, si el signed char tiene una longitud de 8 bits, tiene 8 bits de capacidad para representar un número.

Tenga en cuenta que estas garantías no se aplican a tipos que no sean tipos de caracteres estrechos.

Tipos enteros

Los tipos de enteros sin signo utilizan un sistema binario puro, pero pueden contener bits de relleno. Por ejemplo, es posible (aunque improbable) que un unsigned int tenga una longitud de 64 bits pero solo sea capaz de almacenar enteros entre 0 y 2 32 - 1, ambos inclusive. Los otros 32 bits serían bits de relleno, que no deberían escribirse directamente.

Los tipos de enteros con signo utilizan un sistema binario con un bit de signo y posiblemente bits de relleno. Los valores que pertenecen al rango común de un tipo entero con signo y el tipo entero sin signo correspondiente tienen la misma representación. Por ejemplo, si el patrón de bits 0001010010101011 de un objeto unsigned short representa el valor 5291 , entonces también representa el valor 5291 cuando se interpreta como un objeto short .

Se define por la implementación si se utiliza el complemento de dos, el complemento de uno o la representación de magnitud de signo, ya que los tres sistemas satisfacen el requisito del párrafo anterior.

Tipos de punto flotante

La representación del valor de los tipos de punto flotante está definida por la implementación. Más comúnmente, los tipos float y double ajustan a IEEE 754 y tienen una longitud de 32 y 64 bits (así, por ejemplo, float tendría 23 bits de precisión que seguirían 8 bits de exponente y 1 bit de signo). Sin embargo, la norma no garantiza nada. Los tipos de punto flotante a menudo tienen "representaciones de trampa", que causan errores cuando se usan en los cálculos.

Arrays

Un tipo de matriz no tiene relleno entre sus elementos. Por lo tanto, una matriz con el tipo de elemento T es solo una secuencia de objetos T dispuestos en memoria, en orden.

Una matriz multidimensional es una matriz de matrices, y lo anterior se aplica recursivamente. Por ejemplo, si tenemos la declaración.

int a[5][3];

entonces a es una matriz de 5 matrices de 3 int s. Por lo tanto, a[0] , que consiste en los tres elementos a[0][0] , a[0][1] , a[0][2] , se presenta en la memoria antes de a[1] , que consiste en de a[1][0] , a[1][1] , y a[1][2] . Esto se llama fila orden mayor .



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow