Если я запускаю этот код:
std::cout << static_cast<uint8_t>(65);
Это выведет:
Что является эквивалентом ASCII числа 65.
Это потому что uint8_t
просто определяется как:
typedef unsigned char uint8_t;
Это стандартное поведение?
Не должно быть лучшего способа определить uint8_t
что гарантированно будет рассматриваться как число, а не как символ?
Я не могу понять логику, что если я хочу напечатать значение uint8_t
переменная, она будет напечатана как символ.
Постскриптум Я использую MSVS 2013.
Публикация ответа, поскольку в комментариях есть некоторая дезинформация.
uint8_t
может или не может быть typedef для char
или же unsigned char
, Также возможно, чтобы это был расширенный целочисленный тип (и, следовательно, не символьный тип).
Компиляторы могут предлагать другие целочисленные типы помимо минимального набора, требуемого стандартом (short
, int
, long
, так далее). Например, некоторые компиляторы предлагают 128-битный целочисленный тип.
Это также не будет «конфликтовать с C», поскольку C и C ++ допускают расширенные целочисленные типы.
Итак, ваш код должен учитывать обе возможности. Предложение в комментариях использования одинарного +
должно сработать.
Лично я думаю, что было бы более разумно, если бы стандарт требовал uint8_t
в не быть типом персонажа, так как поведение, которое вы заметили, не интуитивно понятно.
Это косвенно стандартное поведение, потому что ostream
имеет перегрузку для unsigned char
а также unsigned char
является typedef для того же типа uint8_t
в вашей системе.
§27.7.3.1 [output.streams.ostream] дает:
template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, unsigned char);
Я не мог найти нигде в стандарте, который явно заявил, что uint8_t
а также unsigned char
имел быть таким же, хотя. Просто разумно, что они занимают 1 байт почти во всех реализациях.
std::cout << std::boolalpha << std::is_same<uint8_t, unsigned char>::value << std::endl; // prints true
Чтобы получить значение для печати в виде целого числа, вам нужен тип, который не unsigned char
(или одна из других перегрузок символов). Вероятно, простое приведение к uint16_t
достаточно, потому что стандарт не перечисляет перегрузку для него:
uint8_t a = 65;
std::cout << static_cast<uint16_t>(a) << std::endl; // prints 65
Стандартное ли это поведение?
Поведение стандартно в том, что если uint8_t
является определением типа unsigned char
тогда он всегда будет печатать символ как std::ostream
имеет перегрузку для unsigned char
и распечатывает содержимое переменной в виде символа.
Не должно быть лучшего способа определить
uint8_t
что гарантированно будет рассматриваться как число, а не как символ?
Чтобы сделать это, комитет C ++ должен был бы ввести новый фундаментальный тип. В настоящее время единственные типы, которые имеют sizeof()
что равно 1 char
, signed char
, а также unsigned char
, Возможно, они могли бы использовать bool
но bool
не должен иметь размер 1, а затем вы все еще в той же лодке, так как
int main()
{
bool foo = 42;
std::cout << foo << '\n';
}
распечатает 1
не 42
поскольку любое ненулевое значение true, а true печатается как 1
но по умолчанию.
Я не говорю, что это не может быть сделано, но это много работы для чего-то, что может быть обработано с помощью актерский состав или функция
C ++ 17 вводит std::byte
который определяется как enum class byte : unsigned char {};
, Так что он будет шириной в один байт, но это не символьный тип. К сожалению, так как это enum class
это идет со своими собственными ограничениями. Для него были определены побитовые операторы, но для него нет встроенных потоковых операторов, поэтому вам нужно определить свои собственные для ввода и вывода. Это означает, что вы все еще конвертируете его, но по крайней мере вы не будете конфликтовать со встроенными операторами для unsigned char
, Это дает вам что-то вроде
std::ostream& operator <<(std::ostream& os, std::byte b)
{
return os << std::to_integer<unsigned int>(b);
}
std::istream& operator <<(std::istream& is, std::byte& b)
{
unsigned int temp;
is >> temp;
b = std::byte{b};
return is;
}
int main()
{
std::byte foo{10};
std::cout << foo;
}