我有以下代码:
short myShort = 23948;
byte myByte = (byte)myShort;
现在我没想到myByte
会包含值 23948。我猜想它会包含 255(我相信一个字节的最大值)。
但是,它包含 140 个,这让我想知道为什么;幕后究竟发生了什么?
请注意,我不是在找人来解决 23948 无法放入一个字节的问题,我只是想知道底层的实现
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
}
}
}
基本上它只需要最后 8 位......但总的来说,当你发现一些让你感到惊讶的行为时,下一步应该是查阅规范。从第 6.2.1 节开始,我特别强调了与这种情况相关的情况。
对于从一个整数类型到另一个整数类型的转换,处理取决于发生转换的溢出检查上下文(第 7.6.12 节):
- 在检查的上下文中,如果源操作数的值在目标类型的范围内,则转换成功,但如果源操作数的值超出目标类型的范围,则抛出 System.OverflowException。
- 在未经检查的上下文中,转换始终成功,并按如下方式进行。
- 如果源类型大于目标类型,则源值通过丢弃其“额外”最高有效位来截断。然后将结果视为目标类型的值。
- 如果源类型小于目标类型,则源值是符号扩展的或零扩展的,因此它与目标类型的大小相同。如果源类型已签名,则使用符号扩展;如果源类型是无符号的,则使用零扩展。然后将结果视为目标类型的值。
- 如果源类型与目标类型的大小相同,则源值被视为目标类型的值。
这取决于; 在一个checked
上下文中,你会得到一个很大的异常;在unchecked
上下文(默认)中,您可以保留最后一个字节的数据,就像您这样做一样:
byte b = (byte)(value & 255);
在您的特定情况下,当您查看值的位时,行为非常简单:
short myShort = 0x5D8C; // 23948
byte myByte = (byte)myShort; // myShort & 0xFF
Console.WriteLine("0x{0:X}", myByte); // 0x8C or 140
仅保留最后 8 位。二进制的 23948 是 101110110001100b。最后 8 位是 10001100b,等于 140。
当您将整数类型转换为“较小”的整数类型时,只考虑较小的权重位。从数学上讲,就好像您使用了模运算一样。所以你得到值 140 因为 23948 模 256 是 140。
将 long 转换为 int 将使用相同的机制。
当你这样做时,结果是一样的:
byte myByte = (byte)(myShort & 0xFF);
八位以上的一切都被简单地丢弃了。23948 (0x5D8C) 的低八位是 140 (0x8C)。
嗯...因为当您将短(2 个字节)转换为字节(1 个字节)时,它只获得第一个字节,并且 23948 的第一个字节代表 140。
23948 % 256 = 140,转换后最高有效字节丢失,所以输出为140
这就像当你有一个两位数“97”,并将其转换为一位数时,你失去了 9,只保留了“7”