Тип данных uint8 t

Тип данных uint8 t

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

Ч асто необходимо работать не просто с какими-то целыми, а с числами известной, фиксированной длины. Работа с целыми числами одного типа, но разной длины сильно усложняет написание переносимого кода и приводит к массе ошибок. К счастью, в стандарте си предусмотрены типы с известными размерами.

Целые типы фиксированной ширины

Название Знак Размер, бит Размер, байт
int8_t signed 8 1
uint8_t unsigned 8 1
int16_t signed 16 2
uint16_t unsigned 16 2
int32_t signed 32 4
uint32_t unsigned 32 4
int64_t signed 64 8
uint64_t unsigned 64 8

Эти типы имеют гарантированный непрерывный размер, если объявлены. К сожалению, по стандарту они могут и не существовать. Также иногда встречаются и более крупные по размеру типы, например int128_t, но это уже экзотика.

Эти типы объявлены в заголовочном файле stdint.h.

Кроме этих типов, есть ещё несколько важный.

intmax_t и uintmaxt – знаковые и беззнаковые целочисленные типы с максимальной поддерживаемой длиной на данной платформе. Для вывода на печать (с помощью функции printf) используется модификатор j и ju.

Более того, имеется ещё несколько специфических типов.

uint_fast32_t – тип, который может вмещать 32 бита, но на данной платформе работает максимально эффективно (например, 8 байтный на x64 архитектуре).

Также объявлены типы

uint_fast8_t
uint_fast16_t
uint_fast32_t
uint_fast64_t
int_fast8_t
int_fast16_t
int_fast32_t
int_fast64_t

uint_least32_t – Тип с самым маленьким размером, который гарантированно может вместить 32 бита (например, если на данном компьютере целые 64 бита, а 32-битных нет).

Также объявлены типы

int_least8_t
int_least16_t
int_least32_t
int_least64_t
uint_least8_t
uint_least16_t
uint_least32_t
uint_least64_t

Также, вместе с этими типами объявлены константы с соответствующими именами, которые помогают оперировать с числами. Например минимальные значения

INT8_MIN
INT16_MIN
INT32_MIN
INT64_MIN

INT8_MAX
INT16_MAX
INT32_MAX
INT64_MAX

Для least и fast объявлены соответствующие значения INT_LEAST8_MAX и INT_FAST8_MAX и т.п.

Пример. Пусть платформа little endian (а другой вы и найдёте). Пользователь вводит целое число, не более 8 байт длиной. Необходимо вывести, сколько в этом числе ненулевых байт. Для начала, просто выведем побайтно целое. Для этого считаем его в 8 байтное целое

SCNd64 – это макрос, определённый в библиотеке inttypes. Он используется для ввода целых 64 битных чисел. Напомню, что в си строковые литералы, записанные рядом, конкатенируются.

Далее, если у нас есть адрес переменной, то мы можем пройти по каждому байту этой переменной. Для этого приведём её к типу указатель на unsigned char (то есть один байт), а потом будем работать с этим указателем как с массивом.

Теперь уже совсем просто узнать, сколько ненулевых байт в числе

Этот цикл можно переписать множеством разных способов.

Учитывая эту программу C ++ 11, я должен ожидать увидеть число или букву? Или не делать ожидания?

Стандарт определяет, может ли этот тип быть или будет типом символа?

Решение

Из § 18.4.1 [cstdint.syn] FDIS C ++ 0x (N3290), int8_t является необязательным typedef, который указывается следующим образом:

§ 3.9.1 [basic.fundamental] гласит:

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

Типы bool , char , char16_t , char32_t , wchar_t и целочисленные типы со знаком и без знака вместе называются интегральные типы. Синоним для целочисленного типа: целочисленный тип.

§ 3.9.1 также гласит:

В любой конкретной реализации, простой char Объект может принимать либо те же значения, что и signed char или unsigned char ; какой из них определяется реализацией.

Заманчиво сделать вывод, что int8_t может быть typedef char предоставлена char объекты принимают подписанные значения; однако это не тот случай, когда char не входит в список целочисленные типы со знаком (стандартные и, возможно, расширенные целочисленные типы со знаком). Смотрите также Комментарии Стефана Т. Лававея на std::make_unsigned а также std::make_signed ,

Поэтому либо int8_t является определением типа signed char или это расширенный целочисленный тип со знаком, чьи объекты занимают ровно 8 бит памяти.

Чтобы ответить на ваш вопрос, вы не должны делать предположений. Потому что функции обеих форм x.operator а также operator были определены, § 13.5.3 [over.binary] говорит, что мы обращаемся к § 13.3.1.2 [over.match.oper], чтобы определить интерпретацию std::cout , § 13.3.1.2, в свою очередь, говорит, что реализация выбирает из набора функций-кандидатов согласно § 13.3.2 и § 13.3.3. Затем мы смотрим на § 13.3.3.2 [over.ics.rank], чтобы определить, что:

  • template basic_ostream & operator &, signed char) шаблон будет вызван, если int8_t такое точное совпадение для signed char (то есть определение типа signed char ).
  • В противном случае int8_t будет повышен до int и basic_ostream & operator функция-член будет вызвана.
Читайте также:  Биос не видит жесткий диск что делать

В случае std::cout за u uint8_t объект:

  • template basic_ostream & operator &, unsigned char) шаблон будет вызван, если uint8_t такое точное совпадение для unsigned char ,
  • В противном случае, так как int может представлять все uint8_t значения, uint8_t будет повышен до int и basic_ostream & operator функция-член будет вызвана.

Если вы всегда хотите напечатать символ, самый безопасный и понятный вариант:

И если вы всегда хотите напечатать номер:

Другие решения

int8_t ровно 8 бит в ширину (если он существует).

Единственными предопределенными целочисленными типами, которые могут быть 8 битами, являются char , unsigned char , а также signed char , И то и другое short а также unsigned short должны быть не менее 16 бит.

Так int8_t должен быть typedef для любого signed char или простой char (последний, если обычный char подписано).

Если вы хотите распечатать int8_t значение как целое число, а не как символ, вы можете явно преобразовать его в int ,

В принципе, компилятор C ++ может определять 8-битный расширенный целочисленный тип (возможно, называется что-то вроде __int8 ), и сделать int8_t typedef для этого. Единственная причина, по которой я могу это сделать, — это избегать int8_t тип персонажа. Я не знаю ни одного компилятора C ++, который бы на самом деле сделал это.

И то и другое int8_t и расширенные целочисленные типы были введены в C99. Для C нет особой причины определять 8-битный расширенный целочисленный тип, когда char типы доступны.

ОБНОВИТЬ:

Я не совсем доволен этим выводом. int8_t а также uint8_t были введены в C99. В C не имеет особого значения, являются ли они типами символов или нет; нет операций, для которых различие имеет реальное значение. (Четное putc() , процедура вывода символов самого низкого уровня в стандарте C, принимает символ для печати как int аргумент). int8_t , а также uint8_t если они определены, почти наверняка будут определены как символьные типы — но символьные типы — это просто маленькие целочисленные типы.

C ++ предоставляет конкретные перегруженные версии operator за char , signed char , а также unsigned char , чтобы std::cout а также std::cout производить очень разные результаты. Позже, C ++ принял int8_t а также uint8_t , но таким образом, что, как и в C, они почти наверняка являются символьными типами. Для большинства операций это не имеет значения больше, чем в C, но для std::cout это имеет значение, так как это:

вероятно напечатает письмо A а не количество 65 ,

Если вы хотите последовательного поведения, добавьте приведение:

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

Для намерение, Я могу предположить, что члены комитета либо не думали о проблеме, либо решили, что ее не стоит решать. Можно утверждать (и я бы), что преимущества добавления [u]int*_t типы к стандарту перевешивает неудобство их довольно странного поведения с std::cout ,

Имеющаяся у меня рабочая черновая копия N3376 указывает в [cstdint.syn] § 18.4.1, что типами int обычно являются typedefs.

Поскольку единственное требование состоит в том, что оно должно быть 8 битами, тогда typedef to char является приемлемым.

Я отвечу на ваши вопросы в обратном порядке.

Стандарт определяет, может ли этот тип быть или будет типом символа?

Короткий ответ: int8_t является signed char на самых популярных платформах (GCC / Intel / Clang в Linux и Visual Studio в Windows), но могут быть и другими.

Длинный ответ следует.

Раздел 18.4.1 стандарта C ++ 11 содержит краткий обзор который включает в себя следующее

typedef целочисленный тип со знаком int8_t; //optional

Позже в том же разделе, параграф 2, говорится

Заголовок [ ] определяет все функции, типы и макросы так же, как 7.18 в Стандарт C.

где C стандарт означает C99 согласно 1.1 / 2:

C ++ — это язык программирования общего назначения, основанный на языке программирования C, как описано в ISO / IEC 9899: 1999 Языки программирования — C (далее именуемый Стандарт C).

Отсюда и определение int8_t находится в разделе 7.18 стандарта C99. Точнее, в разделе 7.18.1.1 C99 говорится

typedef название intN_t обозначает целочисленный тип со знаком с шириной N без дополнительных битов и представления дополнения до двух. Таким образом, int8_t обозначает целочисленный тип со знаком шириной ровно 8 бит.

Кроме того, в разделе 6.2.5 / 4 раздела C99 говорится

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

Наконец, раздел 5.2.4.2.1 раздела C99 устанавливает минимальные размеры для стандартных целочисленных типов со знаком. Исключая signed char все остальные имеют длину не менее 16 бит.

Читайте также:  Определите общую емкость конденсаторов схема включения

Следовательно, int8_t либо signed char или расширенный (нестандартный) целочисленный тип со знаком 8 бит.

И glibc (библиотека GNU C), и библиотека Visual Studio C определяют int8_t как signed char , Intel и Clang, по крайней мере в Linux, также используют libc, и, следовательно, то же самое относится и к ним. Поэтому на самых популярных платформах int8_t является signed char ,

Учитывая эту программу C ++ 11, я должен ожидать увидеть число или букву? Или не делать ожидания?

Короткий ответ: На самых популярных платформах (GCC / Intel / Clang в Linux и Visual Studio в Windows) вы обязательно увидите букву «A». На других платформах вы можете увидеть 65 хоть. (Благодаря DYP за указание на это мне.)

В дальнейшем все ссылки на стандарт C ++ 11 (текущий проект, N3485).

Раздел 27.4.1 предоставляет краткий обзор В частности, в нем говорится о cout :

Сейчас, ostream это typedef для шаблонной специализации basic_ostream согласно Разделу 27.7.1:

В разделе 27.7.3.6.4 приводится следующая декларация:

Если int8_t является signed char тогда эта перегрузка будет вызвана. В этом же разделе также указывается, что результатом этого вызова является печать символа (а не числа).

Теперь давайте рассмотрим случай, когда int8_t является расширенным целочисленным типом со знаком. Очевидно, что стандарт не определяет перегрузки operator для нестандартных типов, но благодаря акциям и преобразованиям, одна из предоставленных перегрузок может принять вызов. В самом деле, int длиной не менее 16 бит и может представлять все значения int8_t , Тогда 4.5 / 1 дает это int8_t может быть способствовало в int , С другой стороны, 4.7 / 1 и 4.7 / 2 дают это int8_t может быть переоборудованный в signed char , Наконец, 13.3.3.1.1 дает то, что продвижение предпочтительнее, чем преобразование во время разрешения перегрузки. Следовательно, следующая перегрузка (объявлена ​​в 23.7.3.1)

basic_ostream& basic_ostream :: оператор 65 ,

Обновить:

1. Исправил пост следующий DYP комментарий.

2. Добавлены следующие комментарии о возможности int8_t быть typedef за char ,

Как уже говорилось, стандарт C99 (приведенный выше раздел 6.2.5 / 4) определяет 5 стандартных целочисленных типов со знаком ( char не является одним из них) и позволяет реализациям добавлять свои onw, которые называются нестандартными целочисленными типами со знаком. Стандарт C ++ подкрепляет это определение в Разделе 3.9.1 / 2:

Существует пять стандартных типов целых чисел со знаком: «знаковый символ», «короткое целое», «int», «длинное целое» и «длинное длинное целое» […] Также могут существовать типы расширенных целых чисел со знаком, определенные реализацией. Стандартные и расширенные целочисленные типы со знаком называются вместе целочисленные типы со знаком.

Позже, в том же разделе, пункт 7 гласит:

Типы bool , char , char16_t , char32_t , wchar_t , и целочисленные типы со знаком и без знака все вместе называются интегральные типы. Синоним для целочисленного типа: целочисленный тип.

Следовательно, char целочисленный тип, но char не является ни целочисленным типом со знаком, ни целочисленным типом без знака и раздел 18.4.1 (цитируется выше) говорит, что int8_t , когда присутствует, является typedef для целого типа со знаком.

Что может быть запутанным, так это то, что, в зависимости от реализации, char может принимать те же значения, что и signed char , Особенно, char может иметь знак, но это все еще не signed char , Это прямо сказано в разделе 3.9.1 / 1:

[…] Обычный char , signed char , а также unsigned char являются три разных типа. […] В любой конкретной реализации, простой char Объект может принимать либо те же значения, что и signed char или unsigned char ; какой из них определяется реализацией.

Это также подразумевает, что char является не целочисленный тип со знаком, как определено в 3.9.1 / 2.

Читайте также:  Computer configuration administrative templates system

3. Я признаю, что мое толкование и, в частности, предложение « char не является ни знаковый целочисленный тип, ни целое число без знака типа»является несколько спорным.

В подтверждение своего положения я хотел бы добавить, что Стефан Т. Лававей сказал то же самое. Вот а также Йоханнес Шауб — Литб также использовал то же предложение в комментарии к этот сообщение.

char / signed char / unsigned char три разных типа, и char не всегда 8 бит. на большинстве платформ они все 8-битные целые, но в std :: ostream определена только версия char >> для поведения, как scanf("%c", . ) ,

Обновл. 7 Янв 2020 |

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

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

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

Поэтому идеальным вариантом будет избегать использования 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 в программе.

Ссылка на основную публикацию
Adblock detector