Что означает стандарт С++ для размера int, длинного типа?

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

Но существуют ли какие-либо стандарты для С++?

Я использую 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 (и другие типы, которые я не думал of) под разными архитектурами и компиляторами.

Ответ 1

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

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

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

  1. signed char: от -127 до 127 (обратите внимание, но не от -128 до 127; в нем предусмотрены платформы "1-дополнение" и "знак-величина")
  2. unsigned char: от 0 до 255
  3. "обычный" 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> в C или <climits> в C++ (или даже лучше, в шаблонном 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();

Ответ 2

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

Для 64-битных систем основным стандартом Unix de facto является 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 script.

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

Ответ 3

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

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

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

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

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

Ответ 4

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

Стандарт 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 бит и т.д.

Ответ 5

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

Ответ 6

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

  • long long int
  • unsigned long long 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
  • Плюс неподписанные версии.

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

Ответ 7

С++ Standard говорит следующее:

3.9.1, §2:

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

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

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

Ответ 8

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

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

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

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

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

Ответ 9

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

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

typedef int int32;

int32 i;
int32 j;
...

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

typedef long int int32;

int32 i;
int32 j;
...

Ответ 10

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

Ответ 11

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

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

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

#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, которые определены в стандарте.

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

Ответ 13

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

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

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

Ответ 14

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

"Существует пять стандартных стандартных целочисленных типов: подписанный 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

Ответ 15

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

Ответ 16

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

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

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

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

Ответ 17

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

Идея очень проста: создайте список, содержащий типы 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, также объявленный в этом заголовке.

КОДЕКС НИЖЕ НЕ ДАЕТ БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ПОЖАЛУЙСТА, ДВОЙНАЯ ПРОВЕРКА ЭТО.
Я НОВЫЙ В МЕТАПРОГРАММИРОВАНИИ СЛИШКОМ, ЧУВСТВУЮТ, ЧТОБЫ ИЗМЕНИТЬ И ИСПРАВИТЬ ЭТОТ КОД.
Протестировано с DevС++ (поэтому версия 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;

}

Ответ 18

unsigned char bits = sizeof(X) << 3;

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

Ответ 19

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

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

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

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

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

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

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

С

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

С++:

#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 байта long: 4 байта float: 4 байта double: 8 байт

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

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

Ответ 20

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

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

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

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

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

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

Ответ 22

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

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

Ответ 23

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

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

Ответ 24

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

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