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

  Юрий  | 

    | 

  Обновл. 26 Мар 2019  | 

 12890

 ǀ   5 

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

Почему размер целочисленных типов не фиксированный?

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

Разве это не глупо?


Может быть. Программистам не всегда удобно иметь дело с переменными, размер которых варьируется в зависимости от компьютерной архитектуры.

Целочисленные типы фиксированного размера

Чтобы решить вопрос кроссплатформенности, в С++ добавили набор целочисленных типов фиксированного размера, которые гарантированно имеют один и тот же размер на любой архитектуре:

Название Тип Диапазон значений
int8_t 1 байт signed от -128 до 127
uint8_t 1 байт unsigned от 0 до 255
int16_t 2 байта signed от -32 768 до 32 767
uint16_t 2 байта unsigned от 0 до 65 535
int32_t 4 байта signed от -2 147 483 648 до 2 147 483 647
uint32_t 4 байта unsigned от 0 до 4 294 967 295
int64_t 8 байт signed от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807
uint64_t 8 байт unsigned от 0 до 18 446 744 073 709 551 615

Начиная с C++11 доступ к этим типам осуществляется через подключение заголовочного файла cstdint (находятся эти типы данных в пространстве имён std). Рассмотрим пример на практике:

Поскольку целочисленные типы фиксированного размера были добавлены ещё до 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 могут работать не так, как вы ожидаете. Например:

На большинстве архитектурах результат выполнения этой программы следующий:

A

Т.е. программа выше обрабатывает myint как переменную типа char. Однако на некоторых компьютерах результат может быть следующим:

65

Поэтому идеальным вариантом будет избегать использования std::int8_t и std::uint8_t вообще (используйте вместо них std::int16_t или std::uint16_t). Однако, если вы используете std::int8_t или std::uint8_t, то вы должны быть осторожны с любой функцией, которая может интерпретировать std::int8_t или std::uint8_t как символьный тип, вместо целочисленного (например, с объектами std::cin и std::cout).

Правило: Избегайте использования std::int8_t и std::uint8_t. Если вы используете эти типы, то будьте внимательны, так как в некоторых случаях они могут быть обработаны как тип char.

Недостатки целочисленных типов фиксированного размера

Целочисленные типы фиксированного размера могут не поддерживаться на определённых архитектурах (где они не имеют возможности быть представлены). Также эти типы могут быть менее производительными, чем фундаментальные типы данных, на определённых архитектурах.

Спор насчёт unsigned


Многие разработчики (и даже большие организации) считают, что программисты должны избегать использования целочисленных типов unsigned вообще. Главная причина — непредсказуемое поведение и результаты, которые могут возникнуть при «смешивании» целочисленных типов signed и unsigned в программе.

Рассмотрим следующий фрагмент кода:

Что произойдёт в этом случае? -1 преобразуется в другое большое число (скорее всего в 4 294 967 295). Но печаль заключается в том, что предотвратить это мы не сможем. C++ свободно конвертирует числа с типов unsigned в типы signed и наоборот без проверки диапазона допустимых значений определённого типа данных. А это, в свою очередь, может привести к переполнению.

Многие современные языки программирования (такие как Java или C#) либо вообще не имеют типов unsigned, либо ограничивают их использование. Бьёрн Страуструп, создатель C++, говорил: «Использовать тип unsigned (вместо signed) для получения ещё одного бита для представления положительных целых чисел, почти никогда не является хорошей идеей».

Это не означает, что вы должны избегать использования типов unsigned вообще — нет. Но если вы их используете, то используйте только там, где это действительно имеет смысл, а также позаботьтесь о том, чтобы не допустить «смешивания» типов unsigned с типами signed (как в примере выше).

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (167 оценок, среднее: 4,95 из 5)
Загрузка...

Комментариев: 5

  1. Аватар Алексей:

    Здравствуйте Юрий, у меня раньше (чуть меньше половины года) спокойно работал Русский язык. Сейчас же он выводит вот это: Яырслш Ярф ШчырсшЫ… и т. д. Подскажите решение, пожалуйста.

  2. Аватар David:

    Юрий, можно вас спросить, можно ли восстановить потерянные знания по с++?

    1. Юрий Юрий:

      Можно, если приложить соответствующих усилий.

  3. Аватар Константин:

    Юра, а как я пойму, что передо мной чума, в смысле собственная версия компилятора фикс цел числ типа?

  4. Аватар Алексей:

    По поводу фиксированные типов, наткнулся тут на статейку:
    "Процессоры с 36-битной архитектурой как правило имеют 9-битный байт, а в некоторых DSP от Texas Instruments байты состоят из 16 или 32 бит. Древние архитектуры могут иметь короткие байты из 4, 5 или 7 бит."
    И для таких систем приведенные типы не будут работать, так как в них не существует int8_t = 8 байтам.
    Поэтому надежнее использовать:
    int_leastN_t (int_least8_t … int_least64_t; uint_least8_t … uint_least64_t) — минимальный целочисленный тип шириной не менее N бит.
    и int_fastN_t(int_fast8_t … int_fast64_t; uint_fast8_t … uint_fast64_t) — самый быстро обрабатываемый системой целочисленный тип шириной не менее N бит.

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *