Ответ 1
Это довольно просто. Он просто добавляет и отрывается на число с более чем 8 бит. Девятый бит (один) просто "падает", и вы остаетесь с остальными 8 битами, которые образуют число 94.
(да, это безобидно)
Что на самом деле происходит при переполнении байта?
Скажем, что
byte byte1 = 150; // 10010110
byte byte2 = 199; // 11000111
Если мы сделаем это дополнение
byte byte3 = byte1 + byte2;
Думаю, мы закончим с byte3 = 94, но что на самом деле происходит? Я каким-то образом переписал какую-то другую память или это абсолютно безвредно?
Это довольно просто. Он просто добавляет и отрывается на число с более чем 8 бит. Девятый бит (один) просто "падает", и вы остаетесь с остальными 8 битами, которые образуют число 94.
(да, это безобидно)
В С#, если у вас
checked { byte byte3 = byte1 + byte2; }
Он выдает исключение переполнения. Код компилируется unchecked
по умолчанию. Как говорят другие ответы, значение "обернется". т.е. byte3 = (byte1 + byte2) & 0xFF;
Верхние биты будут усечены. Это не вредно для любой другой памяти, это вредно только в плане непредвиденных результатов.
Флаг переноса устанавливается... но помимо результата, который не является тем, что вы ожидаете, не должно быть никаких негативных последствий.
Обычно (и точное поведение будет зависеть от языка и платформы), результат будет получен по модулю 256. т.е. 150 + 199 = 349. 349 mod 256 = 93.
Это не должно влиять на какое-либо другое хранилище.
Поскольку вы отметили свой вопрос С#, С++ и C, я отвечу о C и С++. В переполнении С++ для подписанных типов, в том числе sbyte
(который, я считаю, signed char
в C/С++) приводит к поведению undefined. Однако для неподписанных типов, таких как byte
(который является unsigned char
в С++), результат принимает по модулю 2 n где n - количество бит в неподписанном типе. В С# выполняется второе правило, и подписанные типы генерируют исключение, если они находятся в блоке checked
. Возможно, я ошибаюсь в части С#.
Переполнение безвредно в С# - вы не будете переполнять память - вы просто обловы получаете последние 8 бит результата. Если вы хотите, чтобы это исключение, используйте ключевое слово "checked". Заметим также, что вы можете найти байт + байт, который дает int, поэтому вам может потребоваться отбросить его в байт.
Поведение зависит от языка.
В C и С++ подписанное переполнение undefined, а неподписанное переполнение имеет описанное вами поведение (хотя тип byte
отсутствует).
В С# вы можете использовать ключевое слово checked
, чтобы явно сказать, что хотите получить исключение, если есть переполнение и ключевое слово unchecked
, чтобы явно сказать, что вы хотите его игнорировать.
Ведущий бит просто выпал.
И происходит арифметическое переполнение. Так как 150 + 199 = 349, двоичный 1 0101 1101, верхний 1 бит отбрасывается, а байт становится 0101 1101; то есть количество бит, которое может содержать байты.
Никаких повреждений не было. память не переполнилась в другое место.
Посмотрим, что на самом деле происходит (в C (если у вас есть соответствующий тип данных, так как некоторые указали, что C не имеет типа байтов), тем не менее, существуют 8-битные типы данных, которые могут быть добавлено)). Если эти байты объявлены в стеке, они существуют в основной памяти; в какой-то момент байты будут скопированы в процессор для работы (я пропускаю несколько важных шагов, таких как кэширование процессов...). Однажды в процессоре они будут храниться в регистрах; процессор будет выполнять операцию добавления для этих двух регистров, чтобы добавить данные вместе. Здесь возникает причина путаницы. ЦП будет выполнять операцию добавления в нативном (или иногда заданном) типе данных. Пусть говорят, что родной тип процессора - это 32-битное слово (и этот тип данных - это то, что используется для операции добавления); это означает, что эти байты будут сохранены в 32-битных словах с отмененными верхними 24 битами; операция добавления действительно сделает переполнение в целевом 32-битном слове. Но (и здесь важный бит), когда данные копируются обратно из регистра в стек, только самые младшие 8 бит (байт) будут скопированы обратно в место назначения цели в стеке. (Обратите внимание, что здесь есть и сложность, связанная с упаковкой байтов и стеком.)
Итак, вот итог; добавление вызывает переполнение (в зависимости от выбранной выбранной команды процессора); однако данные копируются из процессора в тип данных соответствующего размера, поэтому переполнение невидимо (и безвредно, если предполагается, что он написан правильно).
Что касается С#, добавление двух значений типа byte
вместе приводит к значению типа int
, которое затем должно быть отброшено на byte
.
Поэтому ваш образец кода приведет к ошибке компилятора без возврата к байту, как показано ниже.
byte byte1 = 150; // 10010110
byte byte2 = 199; // 11000111
byte byte3 = (byte)(byte1 + byte2);
Подробнее см. в MSDN. Кроме того, см. спецификацию языка С#, раздел 7.3.6 Числовые рекламные акции.