[C++] Предполагают ли типы int8_t и uint8_t быть символами?


Answers

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 символа int8_t . Я не знаю каких-либо компиляторов C ++, которые действительно это сделали.

В C99 были введены как int8_t и расширенные целочисленные типы. Для 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 << 'A' и std::cout << 65 производят очень разные результаты. Позже C ++ принял int8_t и uint8_t , но таким образом, что, как и в C, они почти наверняка uint8_t типам символов. Для большинства операций это не имеет значения, чем в C, но для std::cout << ... это имеет значение, так как это:

uint8_t x = 65;
std::cout << x;

вероятно, напечатает букву A а не цифру 65 .

Если вам требуется последовательное поведение, добавьте бросок:

uint8_t x = 65;
std::cout << int(x); // or static_cast<int>(x) if you prefer

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

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

Question

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

#include <cstdint>
#include <iostream>

int main()
{
    int8_t i = 65;
    std::cout << i;
}

Указывает ли стандарт, может ли этот тип или быть типом символа?




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

Указывает ли стандарт, может ли этот тип или быть типом символа?

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

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

В разделе 18.4.1 стандарта C ++ 11 приведен краткий обзор <cstdint> который включает следующее

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

Позже в том же параграфе, в пункте 2, говорится:

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

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

C ++ - это язык программирования общего назначения, основанный на языке программирования C, как описано в языках программирования ИСО / МЭК 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

Существует пять стандартных стандартных целочисленных типов , обозначенных как подписанный символ char , short int , int , long int и long long int . (Эти и другие типы могут быть назначены несколькими дополнительными способами, как описано в 6.7.2.) Могут также существовать расширенные типы целочисленных подписей, определенные реализацией . Стандартные и расширенные со знаком целочисленные типы совместно называются целыми типами со знаком .

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

Следовательно, int8_t является либо signed char int8_t , либо длинным расширенным (не стандартным) знаковым целым типом длиной 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 приведен краткий обзор <iostream> , в частности, он содержит декларацию cout :

extern ostream cout;

Теперь ostream - это typedef для шаблонной специализации basic_ostream согласно разделу 27.7.1:

template <class charT, class traits = char_traits<charT> >
class basic_ostream;

typedef basic_ostream<char> ostream;

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

template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, signed char c);

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

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

basic_ostream & basic_ostream :: operator << (int n);

будет вызываться. Это означает, что этот код

int8_t i = 65;
std::cout << i;

напечатает 65 .

Обновить:

1 . Исправлена ​​запись, следующая dyp комментарием dyp .

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

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

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

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

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

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

Что может сбить с толку, так это то, что в зависимости от реализации 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.

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

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




Links