Что в стандарте 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)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
От 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-битные системы имеют тенденцию использовать их и имеют расширения / модификации. Пожалуйста, обратитесь к этому для получения дополнительной информации:
Я заметил, что все остальные ответы здесь были сосредоточены почти исключительно на целочисленных типах, в то время как спрашивающий также задавал вопросы о плавающих точках.
Я не думаю, что этого требует стандарт 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)
= 4sizeof(double)
= 8sizeof(long double)
= 8 или 16
Стандарт C++ не определяет размер целых типов в байтах, но определяет минимальные диапазоны, которые они должны поддерживать. Вы можете вывести минимальный размер в битах из требуемого диапазона. Вы можете вывести минимальный размер в байтах из этого и значения CHAR_BIT
макроса, который определяет количество бит в байте . На всех платформах, кроме самых малоизвестных, это 8, и не может быть меньше 8.
Еще одно ограничение char
заключается в том, что его размер всегда составляет 1 байт или CHAR_BIT
бит (отсюда и название). Это прямо указано в стандарте.
Стандарт C является нормативным справочником для стандарта C++, поэтому, даже несмотря на то, что он не устанавливает эти требования явно, C++ требует минимальных диапазонов, требуемых стандартом C (стр. 22), которые совпадают с диапазонами из диапазонов типов данных на MSDN :
signed char
: От -127 до 127 (примечание, не от -128 до 127; это подходит для платформ с дополнением до единицы и знаками и величинами)unsigned char
: От 0 до 255- "plain"
char
: тот же диапазон, что иsigned char
илиunsigned char
, определяется реализацией signed short
: От -32767 до 32767unsigned short
: От 0 до 65535signed int
: От -32767 до 32767unsigned int
: От 0 до 65535signed long
: От -2147483647 до 2147483647unsigned long
: От 0 до 4294967295signed long long
: От -9223372036854775807 до 9223372036854775807unsigned long long
: 0 на 18446744073709551615
Реализация C++ (или C) может определять размер типа в байтах sizeof(type)
для любого значения, если
- выражение
sizeof(type) * CHAR_BIT
оценивается как количество бит, достаточно высокое, чтобы содержать требуемые диапазоны, и - порядок типов по-прежнему действителен (например
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 .
На практике такого нет. Часто вы можете ожидать 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 для определения ваших переменных. Не то чтобы мне это нравилось, но это самый портативный способ.
Для чисел с плавающей запятой существует стандарт (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>
.
Вывод: это зависит от того, над какой архитектурой вы работаете. Любое другое предположение неверно.