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