Что в стандарте C++ определяет размер типа int, long?

Я ищу подробную информацию о размере основных типов C++. Я знаю, что это зависит от архитектуры (16 бит, 32 бит, 64 бит) и компилятора.

Но есть ли стандарты для C++?

Я использую Visual Studio 2008 на 32-битной архитектуре. Вот что я получаю:

char  : 1 byte
short : 2 bytes
int   : 4 bytes
long  : 4 bytes
float : 4 bytes
double: 8 bytes

Я пытался найти, без особого успеха, достоверную информацию о том , размеры char, short, int, long, double, float (и другие типы я не думал) в различных архитектурах и компиляторов.

Ответов (24)

Для 32-битных систем стандартом «де-факто» является ILP32, то есть int, long и указатель являются 32-битными величинами.

Для 64-битных систем основным стандартом «де-факто» Unix является LP64, long а указатель является 64-битным (но int 32-битным). 64-битный стандарт для Windows является LLP64 - long long и указатель является 64-разрядными (но long и int оба 32-бит).

В свое время некоторые системы Unix использовали организацию ILP64.

Ни один из этих стандартов де-факто не закреплен в стандарте C (ISO / IEC 9899: 1999), но все они разрешены им.

И, по определению, sizeof(char) есть 1, несмотря на тест в скрипте настройки Perl.

Обратите внимание, что были машины (Crays), у которых CHAR_BIT было намного больше 8. Это означало, что IIRC sizeof(int) также был 1, потому что оба char и int были 32-битными.

Нам разрешено определять синоним для типа, чтобы мы могли создать свой собственный «стандарт».

На машине, в которой sizeof (int) == 4, мы можем определить:

typedef int int32;

int32 i;
int32 j;
...

Поэтому, когда мы переносим код на другую машину, где на самом деле размер long int равен 4, мы можем просто переопределить единственное вхождение int.

typedef long int int32;

int32 i;
int32 j;
...

Если вас интересует решение на чистом C++, я использовал шаблоны и только стандартный код C++ для определения типов во время компиляции на основе их битового размера. Это делает решение переносимым между компиляторами.

Идея очень проста: создайте список, содержащий типы char, int, short, long, long long (подписанные и неподписанные версии), просканируйте список и с помощью шаблона numeric_limits выберите тип с заданным размером.

Включая этот заголовок, вы получили 8 типов stdtype :: int8, stdtype :: int16, stdtype :: int32, stdtype :: int64, stdtype :: uint8, stdtype :: uint16, stdtype :: uint32, stdtype :: uint64.

Если какой-либо тип не может быть представлен, он будет оценен как stdtype :: null_type, также объявленный в этом заголовке.

КОД, ПРИВЕДЕННЫЙ БЕЗ ГАРАНТИИ, ПОЖАЛУЙСТА, ПРОВЕРЬТЕ ЕГО ДВОЙНЫМ.
Я тоже новичок в метапрограммировании, не стесняйтесь редактировать и исправлять этот код.
Протестировано с помощью DevC++ (так что версия gcc около 3.5)

#include <limits>

namespace stdtype
{
    using namespace std;


    /*
     * THIS IS THE CLASS USED TO SEMANTICALLY SPECIFY A NULL TYPE.
     * YOU CAN USE WHATEVER YOU WANT AND EVEN DRIVE A COMPILE ERROR IF IT IS 
     * DECLARED/USED.
     *
     * PLEASE NOTE that C++ std define sizeof of an empty class to be 1.
     */
    class null_type{};

    /*
     *  Template for creating lists of types
     *
     *  T is type to hold
     *  S is the next type_list<T,S> type
     *
     *  Example:
     *   Creating a list with type int and char: 
     *      typedef type_list<int, type_list<char> > test;
     *      test::value         //int
     *      test::next::value   //char
     */
    template <typename T, typename S> struct type_list
    {
        typedef T value;
        typedef S next;         

    };




    /*
     * Declaration of template struct for selecting a type from the list
     */
    template <typename list, int b, int ctl> struct select_type;


    /*
     * Find a type with specified "b" bit in list "list"
     *
     * 
     */
    template <typename list, int b> struct find_type
    {   
        private:
            //Handy name for the type at the head of the list
            typedef typename list::value cur_type;

            //Number of bits of the type at the head
            //CHANGE THIS (compile time) exp TO USE ANOTHER TYPE LEN COMPUTING
            enum {cur_type_bits = numeric_limits<cur_type>::digits};

        public:
            //Select the type at the head if b == cur_type_bits else
            //select_type call find_type with list::next
            typedef  typename select_type<list, b, cur_type_bits>::type type;
    };

    /*
     * This is the specialization for empty list, return the null_type
     * OVVERRIDE this struct to ADD CUSTOM BEHAVIOR for the TYPE NOT FOUND case
     * (ie search for type with 17 bits on common archs)
     */
    template <int b> struct find_type<null_type, b>
    {   
        typedef null_type type;

    };


    /*
     * Primary template for selecting the type at the head of the list if
     * it matches the requested bits (b == ctl)
     *
     * If b == ctl the partial specified templated is evaluated so here we have
     * b != ctl. We call find_type on the next element of the list
     */
    template <typename list, int b, int ctl> struct select_type
    {   
            typedef  typename find_type<typename list::next, b>::type type; 
    };

    /*
     * This partial specified templated is used to select top type of a list
     * it is called by find_type with the list of value (consumed at each call)
     * the bits requested (b) and the current type (top type) length in bits
     *
     * We specialice the b == ctl case
     */
    template <typename list, int b> struct select_type<list, b, b>
    {
            typedef typename list::value type;
    };


    /*
     * These are the types list, to avoid possible ambiguity (some weird archs)
     * we kept signed and unsigned separated
     */

    #define UNSIGNED_TYPES type_list<unsigned char,         \
        type_list<unsigned short,                           \
        type_list<unsigned int,                             \
        type_list<unsigned long,                            \
        type_list<unsigned long long, null_type> > > > >

    #define SIGNED_TYPES type_list<signed char,         \
        type_list<signed short,                         \
        type_list<signed int,                           \
        type_list<signed long,                          \
        type_list<signed long long, null_type> > > > >



    /*
     * These are acutally typedef used in programs.
     * 
     * Nomenclature is [u]intN where u if present means unsigned, N is the 
     * number of bits in the integer
     *
     * find_type is used simply by giving first a type_list then the number of 
     * bits to search for.
     *
     * NB. Each type in the type list must had specified the template 
     * numeric_limits as it is used to compute the type len in (binary) digit.
     */
    typedef find_type<UNSIGNED_TYPES, 8>::type  uint8;
    typedef find_type<UNSIGNED_TYPES, 16>::type uint16;
    typedef find_type<UNSIGNED_TYPES, 32>::type uint32;
    typedef find_type<UNSIGNED_TYPES, 64>::type uint64;

    typedef find_type<SIGNED_TYPES, 7>::type    int8;
    typedef find_type<SIGNED_TYPES, 15>::type   int16;
    typedef find_type<SIGNED_TYPES, 31>::type   int32;
    typedef find_type<SIGNED_TYPES, 63>::type   int64;

}

Как ответили другие, все «стандарты» оставляют большую часть деталей как «определяется реализацией» и только заявляют, что тип «char» имеет ширину, по крайней мере, «char_bis», и что «char <= short <= int <= long < = long long "(float и double в значительной степени соответствуют стандартам с плавающей запятой IEEE, а long double обычно совпадает с double - но может быть больше в более современных реализациях).

Одна из причин отсутствия очень конкретных и точных значений заключается в том, что такие языки, как C/C++, были разработаны для переносимости на большое количество аппаратных платформ, включая компьютерные системы, в которых размер слова "char" может быть 4-битным. или 7-битные, или даже какое-то другое значение, отличное от «8- / 16- / 32- / 64-битных» компьютеров, с которыми сталкивается средний пользователь домашнего компьютера. (Размер слова здесь означает, сколько битов обычно работает в системе - опять же, это не всегда 8 бит, как могут ожидать пользователи домашних компьютеров.)

Если вам действительно нужен объект (в смысле серии битов, представляющих целое значение) с определенным числом битов, у большинства компиляторов есть какой-либо способ указать это; Но, как правило, он не переносится даже между компиляторами, созданными компанией Ame, но для разных платформ. Некоторые стандарты и практики (особенно limits.h и т.п.) достаточно распространены, поэтому большинство компиляторов будет поддерживать определение наиболее подходящего типа для определенного диапазона значений, но не количества используемых битов. (То есть, если вы знаете, что вам нужно хранить значения от 0 до 127, вы можете определить, что ваш компилятор поддерживает 8-битный тип int8, который будет достаточно большим, чтобы удерживать весь желаемый диапазон, но не что-то вроде Тип "int7", который будет точным совпадением для 7-битов.)

Примечание. Многие исходные пакеты Un * x использовали сценарий "./configure", который проверяет возможности компилятора / системы и выводит подходящий файл Makefile и config.h. Вы можете изучить некоторые из этих сценариев, чтобы увидеть, как они работают и как они проверяют возможности компилятора / системы, и следовать их примеру.

Когда дело доходит до встроенных типов для разных архитектур и разных компиляторов, просто запустите следующий код в своей архитектуре с вашим компилятором, чтобы увидеть, что он выводит. Ниже показан мой 64-битный вывод g ++ 4.7.3 Ubuntu 13.04 (Raring Ringtail). Также обратите внимание на то, что было дано ниже, поэтому вывод упорядочен как таковой:

«Существует пять стандартных целочисленных типов со знаком: signed char, short int, int, long int и long long int. В этом списке каждый тип обеспечивает по крайней мере такой же объем памяти, как и предшествующие ему в списке».

#include <iostream>

int main ( int argc, char * argv[] )
{
  std::cout<< "size of char: " << sizeof (char) << std::endl;
  std::cout<< "size of short: " << sizeof (short) << std::endl;
  std::cout<< "size of int: " << sizeof (int) << std::endl;
  std::cout<< "size of long: " << sizeof (long) << std::endl;
  std::cout<< "size of long long: " << sizeof (long long) << std::endl;

  std::cout<< "size of float: " << sizeof (float) << std::endl;
  std::cout<< "size of double: " << sizeof (double) << std::endl;

  std::cout<< "size of pointer: " << sizeof (int *) << std::endl;
}


size of char: 1
size of short: 2
size of int: 4
size of long: 8
size of long long: 8
size of float: 4
size of double: 8
size of pointer: 8
unsigned char bits = sizeof(X) << 3;

где X a char, int и long т. д. даст вам размер X в битах.

На 64-битной машине:

int: 4
long: 8
long long: 8
void*: 8
size_t: 8

От Alex B Стандарт C++ не определяет размер целочисленных типов в байтах, но определяет минимальные диапазоны, которые они должны поддерживать. Вы можете вывести минимальный размер в битах из требуемого диапазона. Вы можете вывести минимальный размер в байтах из этого и значения макроса CHAR_BIT, который определяет количество бит в байте (на всех, кроме самых непонятных платформ, это 8, и оно не может быть меньше 8).

Еще одно ограничение для char заключается в том, что его размер всегда равен 1 байту или битам CHAR_BIT (отсюда и название).

Минимальные диапазоны, требуемые стандартом (стр. 22):

и диапазоны типов данных в MSDN:

знаковый символ: от -127 до 127 (примечание, не от -128 до 127; это соответствует платформам с дополнением до 1) беззнаковый символ: от 0 до 255 «простой» символ: от -127 до 127 или от 0 до 255 (зависит от подписи символа по умолчанию) подписанный короткие: от -32767 до 32767 беззнаковые короткие: от 0 до 65535 подписанные int: от -32767 до 32767 беззнаковые int: от 0 до 65535 длинные со знаком: от -2147483647 до 2147483647 длинные без знака: от 0 до 4294967295 длинные со знаком длинные: от -9223372036854775807 до 9223372036854775 От 0 до 18446744073709551615 Реализация C++ (или C) может определять размер типа в байтах sizeof (type) для любого значения, если

выражение sizeof (type) * CHAR_BIT оценивается как количество бит, достаточное для того, чтобы содержать требуемые диапазоны, и порядок типов по-прежнему действителен (например, sizeof (int) <= sizeof (long)). Фактические диапазоны, зависящие от реализации, можно найти в заголовке в C или в C++ (или, что еще лучше, в шаблонных std::numeric_limits в заголовке).

Например, вот как вы найдете максимальный диапазон для int:

C:

#include <limits.h>
const int min_int = INT_MIN;
const int max_int = INT_MAX;

C++:

#include <limits>
const int min_int = std::numeric_limits<int>::min();
const int max_int = std::numeric_limits<int>::max();

Это правильно, однако вы также были правы, говоря, что: char: 1 байт короткий: 2 байта int: 4 байта длиной: 4 байта float: 4 байта double: 8 байтов

Потому что 32-битные архитектуры по-прежнему используются по умолчанию и используются чаще всего, и они сохранили эти стандартные размеры с тех пор, как до 32-битных времен память была менее доступной, а для обратной совместимости и стандартизации она оставалась прежней. Даже 64-битные системы имеют тенденцию использовать их и имеют расширения / модификации. Пожалуйста, обратитесь к этому для получения дополнительной информации:

http://en.cppreference.com/w/cpp/language/types

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

Я не думаю, что этого требует стандарт C++, но компиляторы для наиболее распространенных платформ в наши дни обычно следуют стандарту IEEE754 для своих чисел с плавающей запятой. Этот стандарт определяет четыре типа двоичных чисел с плавающей запятой (а также некоторые форматы BCD, которые я никогда не видел поддержки в компиляторах C++):

  • Половинная точность (binary16) - 11-битное значащее значение, диапазон экспоненты от -14 до 15
  • Одинарная точность (binary32) - 24-битное значащее значение, диапазон экспоненты от -126 до 127
  • Двойная точность (binary64) - 53-битное значащее, диапазон экспоненты от -1022 до 1023
  • Четверная точность (двоичное128) - 113-битное значащее, диапазон экспоненты от -16382 до 16383

Как же тогда эта карта соотносится с типами C++? Обычно float используется одинарная точность; Таким образом, sizeof(float) = 4 . Затем double используется двойная точность (я считаю, что это источник названия double ) и long double может быть либо двойной, либо четырехкратной точностью (в моей системе она четырехкратная, но в 32-битных системах может быть двойной). Я не знаю компиляторов, предлагающих значения с плавающей запятой половинной точности.

В общем, это обычное дело:

  • sizeof(float) = 4
  • sizeof(double) = 8
  • sizeof(long double) = 8 или 16

Стандарт C++ не определяет размер целых типов в байтах, но определяет минимальные диапазоны, которые они должны поддерживать. Вы можете вывести минимальный размер в битах из требуемого диапазона. Вы можете вывести минимальный размер в байтах из этого и значения CHAR_BIT макроса, который определяет количество бит в байте . На всех платформах, кроме самых малоизвестных, это 8, и не может быть меньше 8.

Еще одно ограничение char заключается в том, что его размер всегда составляет 1 байт или CHAR_BIT бит (отсюда и название). Это прямо указано в стандарте.

Стандарт C является нормативным справочником для стандарта C++, поэтому, даже несмотря на то, что он не устанавливает эти требования явно, C++ требует минимальных диапазонов, требуемых стандартом C (стр. 22), которые совпадают с диапазонами из диапазонов типов данных на MSDN :

  1. signed char: От -127 до 127 (примечание, не от -128 до 127; это подходит для платформ с дополнением до единицы и знаками и величинами)
  2. unsigned char: От 0 до 255
  3. "plain" char: тот же диапазон, что и signed charили unsigned char, определяется реализацией
  4. signed short: От -32767 до 32767
  5. unsigned short: От 0 до 65535
  6. signed int: От -32767 до 32767
  7. unsigned int: От 0 до 65535
  8. signed long: От -2147483647 до 2147483647
  9. unsigned long: От 0 до 4294967295
  10. signed long long: От -9223372036854775807 до 9223372036854775807
  11. unsigned long long: 0 на 18446744073709551615

Реализация C++ (или C) может определять размер типа в байтах sizeof(type) для любого значения, если

  1. выражение sizeof(type) * CHAR_BITоценивается как количество бит, достаточно высокое, чтобы содержать требуемые диапазоны, и
  2. порядок типов по-прежнему действителен (например sizeof(int) <= sizeof(long)).

В совокупности мы гарантируем, что:

  • char, signed charи unsigned charне менее 8 бит
  • signed short, unsigned short, signed int, И unsigned int, по крайней мере , 16 бит
  • signed longи unsigned longне менее 32 бит
  • signed long longи unsigned long longне менее 64 бит

Не дается никаких гарантий относительно размера float или double за исключением того, что double обеспечивает по крайней мере такую ​​же точность, как float .

Фактические диапазоны от конкретной реализации могут быть найдены в <limits.h> заголовке в С или <climits> в С ++ (или даже лучше, шаблонные std::numeric_limits в <limits> заголовке).

Например, вот как вы найдете максимальный диапазон для int :

C:

#include <limits.h>
const int min_int = INT_MIN;
const int max_int = INT_MAX;

C++ :

#include <limits>
const int min_int = std::numeric_limits<int>::min();
const int max_int = std::numeric_limits<int>::max();

1) Таблица N1 в статье " Забытые проблемы разработки 64-битных программ "

2) « Модель данных »

Как вы упомянули - это во многом зависит от компилятора и платформы. Для этого проверьте стандарт ANSI, http://home.att.net/~jackklein/c/inttypes.html

Вот компилятор Microsoft: Data Type Ranges .

Как уже упоминалось, размер должен отражать текущую архитектуру. Вы могли бы взглянуть на это, limits.h если хотите увидеть, как ваш текущий компилятор обрабатывает вещи.

На практике такого нет. Часто вы можете ожидать std::size_t представления беззнакового собственного целого числа в текущей архитектуре. т.е. 16-разрядная, 32-разрядная или 64-разрядная, но это не всегда так, как указано в комментариях к этому ответу.

Что касается всех других встроенных типов, это действительно зависит от компилятора. Вот два отрывка из текущего рабочего проекта последнего стандарта C++:

Существует пять стандартных целочисленных типов со знаком: signed char, short int, int, long int и long long int. В этом списке каждый тип обеспечивает по крайней мере такой же объем памяти, как и предыдущие в списке.

Для каждого из стандартных целочисленных типов со знаком существует соответствующий (но другой) стандартный целочисленный тип без знака: unsigned char, unsigned short int, unsigned int, unsigned long int и unsigned long long int, каждый из которых занимает одинаковое количество хранения и имеет те же требования к выравниванию.

Если вы хотите, вы можете статически (во время компиляции) утверждать размер этих фундаментальных типов. Это побудит людей подумать о переносе вашего кода, если предположения о размере изменятся.

Существует стандарт, и он указан в различных стандартах (ISO, ANSI и т. Д.).

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

Однако даже со стандартным компилятором C++ вы можете относительно легко это выяснить, используя следующий фрагмент кода:

#include <iostream>
#include <limits>


int main() {
    // Change the template parameter to the various different types.
    std::cout << std::numeric_limits<int>::max() << std::endl;
}

Документацию по std::numeric_limits можно найти на Roguewave . Он включает в себя множество других команд, которые вы можете вызвать, чтобы узнать о различных ограничениях. Это можно использовать с любым произвольным типом, который передает размер, например std::streamsize.

Ответ Джона содержит лучшее описание, поскольку они гарантированно верны. Независимо от того, на какой платформе вы находитесь, есть еще одна хорошая страница, на которой более подробно описывается, сколько бит ДОЛЖЕН содержать каждый тип: типы int , которые определены в стандарте.

Надеюсь, это поможет!

Нет, стандарта размеров шрифта нет. Стандарт требует только того, чтобы:

sizeof(short int) <= sizeof(int) <= sizeof(long int)

Лучшее, что вы можете сделать, если вам нужны переменные фиксированного размера, - это использовать такие макросы:

#ifdef SYSTEM_X
  #define WORD int
#else
  #define WORD long int
#endif

Затем вы можете использовать WORD для определения ваших переменных. Не то чтобы мне это нравилось, но это самый портативный способ.

Если вам нужны типы фиксированного размера, используйте такие типы, как uint32_t (беззнаковое целое 32 бита), определенные в stdint.h . Они указаны в C99 .

Для чисел с плавающей запятой существует стандарт (IEEE754) : числа с плавающей запятой - 32-битные, а двойные - 64. Это аппаратный стандарт, а не стандарт C++, поэтому компиляторы теоретически могут определять число с плавающей запятой и удвоение для некоторого другого размера, но на практике я ' Я никогда не видел архитектуры, в которой использовалось бы что-нибудь другое.

Обновлено: C++ 11 официально ввел типы из TR1 в стандарт:

  • длинный длинный int
  • беззнаковый длинный длинный int

А «размерные» типы из <cstdint>

  • int8_t
  • int16_t
  • int32_t
  • int64_t
  • (и беззнаковые аналоги).

Плюс вы получаете:

  • int_least8_t
  • int_least16_t
  • int_least32_t
  • int_least64_t
  • Плюс неподписанные аналоги.

Эти типы представляют собой наименьшие целочисленные типы, по крайней мере, с указанным количеством бит. Точно так же существуют «самые быстрые» целочисленные типы, по крайней мере, с указанным количеством битов:

  • int_fast8_t
  • int_fast16_t
  • int_fast32_t
  • int_fast64_t
  • Плюс неподписанные версии.

Что означает «быстро», зависит от реализации. Это не обязательно должно быть самым быстрым для всех целей.

Вы можете использовать переменные, предоставляемые такими библиотеками, как OpenGL , Qt и т. Д.

Например, Qt предоставляет qint8 (гарантированно будет 8-битным на всех платформах, поддерживаемых Qt), qint16, qint32, qint64, quint8, quint16, quint32, quint64 и т. Д.

Есть стандарт.

Стандарт C90 требует, чтобы

sizeof(short) <= sizeof(int) <= sizeof(long)

Стандарт C99 требует, чтобы

sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)

Вот спецификации C99 . На странице 22 указаны размеры различных интегральных типов.

Вот размеры (биты) типа int для платформ Windows:

Type           C99 Minimum     Windows 32bit
char           8               8
short          16              16
int            16              32
long           32              32
long long      64              64

Если вас беспокоит переносимость или вы хотите, чтобы название типа отражало размер, вы можете посмотреть заголовок <inttypes.h>, где доступны следующие макросы:

int8_t
int16_t
int32_t
int64_t

int8_t гарантированно будет 8 бит, int16_t гарантированно будет 16 бит и т. д.

Стандарт C++ говорит об этом так:

3.9.1, §2:

Существует пять целочисленных типов со знаком: «signed char», «short int», «int», «long int» и «long long int». В этом списке каждый тип обеспечивает по крайней мере такой же объем памяти, как и предыдущие в списке. Простые вставки имеют естественный размер, предполагаемый архитектурой среды исполнения (44); другие целочисленные типы со знаком предоставляются для особых нужд.

(44) то есть достаточно большой, чтобы содержать любое значение в диапазоне INT_MIN и INT_MAX, как определено в заголовке <climits> .

Вывод: это зависит от того, над какой архитектурой вы работаете. Любое другое предположение неверно.

Вы можете использовать:

cout << "size of datatype = " << sizeof(datatype) << endl;

datatype = int и long int т. д. Вы сможете увидеть размер любого типа данных, который вы наберете.

В зависимости от размера существует четыре типа целых чисел:

  • короткое целое: 2 байта
  • длинное целое: 4 байта
  • длинное длинное целое: 8 байт
  • целое число: зависит от компилятора (16 бит, 32 бит или 64 бит)