Что на самом деле происходит, когда байтовые переполнения?

StackOverflow https://stackoverflow.com/questions/4156967

  •  08-10-2019
  •  | 
  •  

Вопрос

Что на самом деле происходит, когда байтовые переполнения?

Скажем, у нас есть

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 Числовые акции.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top