Поиск…


замечания

См. Также Размер интегральных типов .

Типы классов

Под «классом» мы подразумеваем тип, который был определен с использованием ключевого слова class или struct (но не enum class enum struct или enum class ).

  • Даже пустой класс по-прежнему занимает как минимум один байт памяти; поэтому он будет состоять из заполнения. Это гарантирует, что если p указывает на объект пустого класса, то p + 1 является отдельным адресом и указывает на отдельный объект. Однако при использовании в качестве базового класса для пустого класса может иметь размер 0. См. Пустую оптимизацию базы .

    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
    
  • Объектное представление типа класса содержит представления объектов базового класса и нестатических типов членов. Поэтому, например, в следующем классе:

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

    существует последовательная последовательность sizeof(int) байтов внутри объекта S , называемая подобъектом, который содержит значение x , и другой подобъект с байтами sizeof(char*) который содержит значение y . Эти два не могут чередоваться.

  • Если тип класса имеет члены и / или базовые классы с типами t1, t2,...tN , размер должен быть не меньше sizeof(t1) + sizeof(t2) + ... + sizeof(tN) учетом предыдущих точек , Однако в зависимости от требований к выравниванию членов и базовых классов компилятору может быть принудительно вставлено дополнение между подобъектами или в начале или конце полного объекта.

    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).
    
  • Если заполнение вставляется в объект из-за требований к выравниванию, размер будет больше, чем сумма размеров членов и базовых классов. При выравнивании n байт размер обычно будет наименьшим кратным n который больше, чем размер всех членов и базовых классов. Каждый член memN , как правило, помещается по адресу, который является кратным alignof(memN) , и n обычно будет самым большим alignof из всех alignof . Из-за этого, если член с меньшим alignof сопровождается элементом с большим alignof , существует вероятность того, что последний элемент не будет правильно выровнен, если он будет установлен сразу после первого. В этом случае прокладка (также известная как элемент выравнивания ) будет помещена между двумя элементами, так что последний элемент может иметь желаемое выравнивание. И наоборот, если для элемента с большим alignof следует элемент с меньшим alignof , обычно никаких alignof не требуется. Этот процесс также известен как «упаковка».
    Из-за того, что классы, обычно разделяющие alignof их члена с наибольшим alignof , классы обычно выравниваются с alignof самого большого встроенного типа, который они прямо или косвенно содержат.

    // 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
  • Если строгое выравнивание принудительно alignas с помощью alignas , то alignas будет использоваться, чтобы заставить тип соответствовать заданному выравниванию, даже если он в противном случае был бы меньшим. Например, с приведенным ниже определением Chars<5> будет иметь три (или, возможно, больше) байта заполнения, вставленные в конец, так что его общий размер равен 8. Невозможно, чтобы класс с выравниванием 4 имел размер из 5, потому что было бы невозможно создать массив этого класса, поэтому размер должен быть «округлен» до кратного 4, вставив прописные байты.

    // 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");
    
  • Если два нестатических члена класса имеют один и тот же спецификатор доступа , то тот, который приходит позже в порядке объявления, гарантированно будет представлен позже в представлении объекта. Но если два нестатических члена имеют разные спецификаторы доступа, их относительный порядок внутри объекта не указан.
  • Не определено, какой порядок субобъекты базового класса появляются внутри объекта, независимо от того, происходят ли они последовательно, и появляются ли они до, после или между субобъектами-членами.

Арифметические типы

Узкие типы символов

Тип unsigned char использует все биты для представления двоичного числа. Поэтому, например, если unsigned char имеет длину 8 бит, то 256 возможных битовых шаблонов объекта char представляют 256 различных значений {0, 1, ..., 255}. Число 42 гарантированно будет представлено битовой диаграммой 00101010 .

signed char тип signed char не имеет битов заполнения, т. Е. Если signed char имеет длину 8 бит, тогда он имеет 8 бит емкости для представления числа.

Обратите внимание, что эти гарантии не применяются к типам, отличным от типов узких символов.

Целочисленные типы

Беззнаковые целые типы используют чистую двоичную систему, но могут содержать биты заполнения. Например, для unsigned int может быть (хотя и маловероятно) иметь длину 64 бита, но только быть способным хранить целые числа от 0 до 2 32 - 1 включительно. Остальные 32 бита будут битами заполнения, которые не должны записываться напрямую.

Подписанные целочисленные типы используют двоичную систему со знаковым битом и, возможно, битами заполнения. Значения, которые относятся к общему диапазону знакового целочисленного типа и соответствующего беззнакового целочисленного типа, имеют одинаковое представление. Например, если битовый шаблон 0001010010101011 unsigned short объекта представляет значение 5291 , тогда он также представляет значение 5291 при интерпретации как short объект.

Определяется реализация, используется ли дополнение двух дополнений, дополнений или знаковых значений, поскольку все три системы удовлетворяют требованию в предыдущем абзаце.

Типы с плавающей точкой

Представление значений типов с плавающей запятой определяется реализацией. Чаще всего float и double типы соответствуют IEEE 754 и имеют длину 32 и 64 бит (так, например, float будет иметь 23 бита точности, которые будут следовать за 8 экспоненциальными битами и 1 знаковым битом). Однако стандарт ничего не гарантирует. Типы плавающей точки часто имеют «ловушечные представления», которые вызывают ошибки, когда они используются в вычислениях.

Массивы

Тип массива не имеет дополнений между его элементами. Следовательно, массив с типом элемента T является просто последовательностью объектов T выложенных в памяти, по порядку.

Многомерный массив представляет собой массив массивов, и приведенное выше относится к рекурсивно. Например, если у нас есть декларация

int a[5][3];

то a представляет собой массив из 5 массивов из 3 int s. Поэтому a[0] , состоящая из трех элементов a[0][0] , a[0][1] , a[0][2] , изложена в памяти до a[1] , которая состоит из из a[1][0] , a[1][1] и a[1][2] . Это называется строчным порядком.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow