Что происходит, когда вы отбрасываете от short to byte в С#?
У меня есть следующий код:
short myShort = 23948;
byte myByte = (byte)myShort;
Теперь я не ожидал, что myByte
будет содержать значение 23948. Я бы предположил, что он будет содержать 255 (я считаю, что наибольшее значение для байта).
Однако он содержит 140, и это заставило меня задаться вопросом, почему; что на самом деле происходит за кулисами?
Обратите внимание, что я не ищу кого-то, чтобы решить проблему, из-за которой 23948 не может поместиться в байт, я просто задаюсь вопросом о базовой реализации
Ответы
Ответ 1
Short - это 2-байтовый тип, а байт - это один байт. Когда вы отбрасываете два байта на один, вы вынуждаете систему делать вещи подходящими, а один из исходных байтов (наиболее значимых) получает отбрасывание и данные теряются. То, что осталось от значения 23948 (двоичный: 0101 1101 1000 1100), равно 140, который в двоичном выражении переводится в 1000 1100. Таким образом, вы переходите от:
0101 1101 1000 1100 (2 byte decimal value 23948)
в
1000 1100 (1 byte decimal value 140)
Вы можете сделать это только с явным приведением. Если вы попытались присвоить короткий байт без броска, компилятор выкинул бы ошибку из-за возможности потери данных:
Невозможно неявно преобразовать тип 'short' в 'byte'. Явный конверсия существует (вам не хватает роли?)
Если вы отбрасываете с байта на короткий, с другой стороны, вы можете делать это неявно, поскольку никакие данные не будут потеряны.
using System;
public class MyClass
{
public static void Main()
{
short myShort = 23948;
byte myByte = (byte)myShort; // ok
myByte = myShort; // error:
Console.WriteLine("Short: " + myShort);
Console.WriteLine("Byte: " + myByte);
myShort = myByte; // ok
Console.WriteLine("Short: " + myShort);
}
}
С арифметическим переполнением и непроверенным контекстом:
using System;
public class MyClass {
public static void Main() {
unchecked {
short myShort = 23948;
byte myByte = (byte)myShort; // ok
myByte = myShort; // still an error
int x = 2147483647 * 2; // ok since unchecked
}
}
}
Ответ 2
В основном, он просто берет последние 8 бит... но в целом, когда вы находите какое-то поведение, которое вас удивляет, следующим шагом должно быть проконсультироваться со спецификацией. Из раздела 6.2.1, с дополнительным вниманием, для ситуации, которая имеет значение в этом случае.
Для преобразования от интегрального типа к другому интегральному типу обработка зависит от контекста проверки переполнения (§7.6.12), в котором происходит преобразование:
- В проверенном контексте преобразование завершается успешно, если значение исходного операнда находится в пределах целевого типа, но генерирует исключение System.OverflowException, если значение исходного операнда находится за пределами диапазона целевого типа.
- В неконтролируемом контексте преобразование всегда выполняется успешно и выполняется следующим образом.
- Если тип источника больше целевого типа, то исходное значение усекается путем отбрасывания его "дополнительных" наиболее значимых бит. Затем результат обрабатывается как значение типа назначения.
- Если тип источника меньше, чем тип адресата, то исходное значение либо расширено, либо равно нулю, так что оно будет такого же размера, как и тип назначения. Расширение знака используется, если тип источника подписан; zero-extension используется, если тип источника неподписан. Затем результат обрабатывается как значение типа назначения.
- Если тип источника имеет тот же размер, что и тип адресата, то исходное значение рассматривается как значение типа назначения.
Ответ 3
В вашем конкретном случае поведение довольно вырезано и сухо, когда вы смотрите на биты для значения:
short myShort = 0x5D8C; // 23948
byte myByte = (byte)myShort; // myShort & 0xFF
Console.WriteLine("0x{0:X}", myByte); // 0x8C or 140
Ответ 4
Это зависит; в контексте checked
вы получите большое толстое исключение; в контексте unchecked
(по умолчанию) вы получаете, чтобы сохранить данные из последнего байта, так же, как если бы вы сделали:
byte b = (byte)(value & 255);
Ответ 5
Сохраняются только последние 8 бит. 23948 в двоичном состоянии - 101110110001100b. Последние 8 бит составляют 10001100b, что равно 140.
Ответ 6
Когда вы вводите целочисленный тип в "меньший" целочисленный тип, учитываются только младшие биты веса. Математически, как будто вы использовали операцию modulo. Таким образом, вы получаете значение 140, потому что 23948 по модулю 256 равно 140.
Приведение длинного к int будет использовать тот же механизм.
Ответ 7
Результат будет таким же:
byte myByte = (byte)(myShort & 0xFF);
Все выше восьми бит просто выброшено. Нижние восемь бит 23948 (0x5D8C) составляют 140 (0x8C).
Ответ 8
Uhm... потому что когда вы вводите короткий (2 байта) в байт (1 байт), он получает только первый байт, а первый байт 23948 представляет 140.
Ответ 9
23948% 256 = 140, наиболее значимые байты были потеряны после преобразования, поэтому выход равен 140
Ответ 10
Например, когда у вас есть двухзначное число "97" и конвертируйте его в однозначное число, вы теряете 9 и сохраняете только "7"