#c #types #casting #char
Вопрос:
Я (думаю, что я) понимаю, как работает математика с различными типами переменных. Например, если я превышу максимальный предел unsigned int
переменной, она вернется к 0
.
Я не понимаю поведения этого кода с unsigned char
:
#include<iostream>
int main() {
unsigned char var{ 0 };
for(int i = 0; i < 501; i) {
var = 1;
std::cout << var << 'n';
}
}
Это просто выводит 1...9
данные , затем некоторые символы и заглавные буквы, а затем просто ничего не печатает. Он не возвращается к значениям 1...9
и т. Д.
С другой стороны, если я приведу к int
этому перед печатью:
#include<iostream>
int main() {
unsigned char var{ 0 };
for(int i = 0; i < 501; i) {
var = 1;
std::cout << (int)var << 'n';
}
}
Он печатает с 1...255
, а затем выполняет обратный цикл 0...255
.
Это почему? Похоже, что unsgined char
переменная выполняет цикл (как мы видим из приведения int).
Безопасно ли заниматься математикой с unsigned char
переменными? Какое поведение я вижу здесь?
Комментарии:
1. Какой компилятор компилирует это, и какую командную строку вы используете для его запуска? Неповторяющееся поведение 1..9 может быть связано с тем, как используемая вами оболочка работает с конкретными непечатаемыми символами (а не с C ).
2. @JohnFilleau я использую
g (GCC) 11.1.0
какg test.cpp -o test
. И просто бежит, как./test
3. Вы видите что-то другое? например, повторяющиеся 1..9?
4. Я вижу повторяющиеся 1..9, а также непечатаемые обозначения до и после набора ASCII. Но 1..9 определенно повторяется.
Ответ №1:
Почему он не выводит ожидаемое целочисленное значение?
Проблема не в цикличности char
. Проблема заключается в операции вставки для std::ostream
объектов и 8-разрядных целочисленных типов. Функции, не являющиеся членами operator<<
для этих типов, обрабатывают все 8-разрядные целые числа ( char
, signed char
, и unsigned char
) как их типы символов ASCII.
Канонический способ обработки вывода 8-разрядных целочисленных типов-это то, как вы это делаете. Я лично предпочитаю это вместо этого:
char foo;
std::cout << foo;
Унарный
оператор преобразует char
тип в integer
тип, который затем вызывает функцию целочисленной печати.
Обратите внимание, что переполнение целых чисел определяется только для unsigned
целочисленных типов. Если вы повторите это с char
или signed char
, поведение не определено стандартом. ЧТО-то обязательно произойдет, потому что мы живем в реальности, но поведение переполнения может отличаться от компилятора к компилятору.
Почему он не повторяет 0..9 символов
Я протестировал это с помощью g
компиляции и bash на Ubuntu 20.04. Мои непечатаемые символы в некоторых случаях обрабатываются как явные символы, а в других случаях ничего не печатается. Неповторяющееся поведение должно быть связано с тем, как ваша оболочка обрабатывает эти непечатаемые символы. Мы не можем ответить на этот вопрос без дополнительной информации.
Ответ №2:
В этом случае символы без знака не рассматриваются как числа. Этот тип данных буквально представляет собой байт:
1 byte = 8 bits = 0000 0000 which means 0.
То, что печатает cout, — это символ, представляющий тот байт, который вы изменили, добавив к нему 1.
Например:
0 = 0000 0000
1 = 0000 0001
2 = 0000 0010
.
.
.
9 = 0000 1001
Затем здесь начинаются другие символы, которые не связаны с числами.
Таким образом, если вы приведете его к int, он даст вам числовые представления этого байта, что даст вам результат 0-255.
Надеюсь, это прояснит ситуацию!
Правка: Сделал объяснение более ясным.
Комментарии:
1. «Символы без знака-это не числа» , так оно и есть. Просто
cout
к ним относятся необычно.2.
unsigned char
является целым числом3. @HolyBlackCat Я имел в виду, что в этом случае они не рассматриваются как числа, но да, я неправильно выразился.