Урок №32. Фиксированный размер целочисленных типов данных

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

С C++11 доступ к указанным типам осуществляется путем включения заголовочного файла cstdint (эти типы данных находятся в пространстве имен std). Рассмотрим пример на практике:
#include
#include
int main ( )
{
std :: int16 _ t i ( 5 ) ; // прямая инициализация
std :: cout << i << std :: endl ;
return 0 ;
}
Так как целочисленные типы фиксированного размера были введены задолго до появления C++11, некоторые устаревшие компиляторы предоставляют доступ к ним через включение заголовочного файла stdint.h.
Если ваш компилятор не поддерживает библиотеки cstdint или stdint.h, то вы можете загрузить универсальный заголовочный файл pstdint.h. Просто добавьте его в ваш проект, и он автоматически определит целочисленные типы фиксированного размера для вашей системы или архитектуры.
Предупреждение насчет std::int8_t и std::uint8_t
Из-за определенных причин в языке программирования C++ большинство компиляторов интерпретируют и обрабатывают типы int8_t и uint8_t так же, как и типы char signed и char unsigned соответственно. Однако, это не всегда так. Поэтому, использование std::cin и std::cout может привести к неожиданным результатам. Например:
#include
#include
int main ( )
{
std :: int8_t myint = 65 ;
std :: cout << myint << std :: endl ;
return 0 ;
}
У большинства компьютеров с различными архитектурами результат работы данной программы будет аналогичным:
A
Другими словами, вышеуказанная программа интерпретирует myint как переменную типа char. Однако на определенных компьютерах результат может отличаться:
65Идеальным вариантом будет избегать использования типов данных std::int8_t и std::uint8_t в целом, вместо них лучше использовать std::int16_t или std::uint16_t. Однако, если все же приходится работать с std::int8_t или std::uint8_t, необходимо быть осторожным при использовании функций, которые могут интерпретировать их как символьный тип, а не как целочисленный (например, с потоками ввода-вывода std::cin и std::cout).
Рекомендация: Старайтесь избегать применения std::int8_t и std::uint8_t. При необходимости использования этих типов, следует быть осторожным, так как в определенных ситуациях они могут быть интерпретированы как тип char.
Недостатки целочисленных типов фиксированного размера
На некоторых архитектурах могут отсутствовать поддержка целочисленных типов фиксированного размера из-за их невозможности представления. Кроме того, на определенных архитектурах эти типы данных могут работать менее эффективно, чем базовые типы данных.
Спор насчет unsigned
Многие специалисты в области разработки программного обеспечения (и даже крупные компании) считают, что программистам следует избегать использования беззнаковых целочисленных типов в целом. Основной аргумент заключается в том, что такой подход может привести к непредсказуемому поведению и результатам при взаимодействии знаковых и беззнаковых целочисленных типов в программе.
Давайте изучим данный участок программного кода:
void doSomething ( unsigned int x )
{
// Выполнение некоего кода x раз
}
int main ( )
{
doSomething ( - 1 ) ;
}
Что произойдет в данном случае? -1 может быть преобразовано в другое большое число (вероятнее всего, в 4 294 967 295). Однако самое печальное в этой ситуации заключается в том, что мы не сможем предотвратить это. Язык программирования C++ позволяет свободно конвертировать числа с типами unsigned в типы signed и наоборот без проверки диапазона допустимых значений конкретного типа данных. Это, в свою очередь, может привести к переполнению.
По мнению Бьёрна Страуструпа, изобретателя языка C++, использование типа unsigned (вместо signed) для получения дополнительного бита для представления положительных целых чисел практически всегда не является оптимальным решением.
Не следует полностью отказываться от использования типов unsigned. Однако, если вы все же решите использовать их, убедитесь, что это действительно необходимо, и избегайте смешивания типов unsigned с signed (как в приведенном выше примере).
Comments