11

我有以下代码:

short myShort = 23948;
byte myByte = (byte)myShort;

现在我没想到myByte会包含值 23948。我猜想它会包含 255(我相信一个字节的最大值)。

但是,它包含 140 个,这让我想知道为什么;幕后究竟发生了什么?

请注意,我不是在找人来解决 23948 无法放入一个字节的问题,我只是想知道底层的实现

4

10 回答 10

15

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
        }   
    }
}
于 2011-09-27T21:07:15.560 回答
6

基本上它只需要最后 8 位......但总的来说,当你发现一些让你感到惊讶的行为时,下一步应该是查阅规范。从第 6.2.1 节开始,我特别强调了与这种情况相关的情况。

对于从一个整数类型到另一个整数类型的转换,处理取决于发生转换的溢出检查上下文(第 7.6.12 节):

  • 在检查的上下文中,如果源操作数的值在目标类型的范围内,则转换成功,但如果源操作数的值超出目标类型的范围,则抛出 System.OverflowException。
  • 在未经检查的上下文中,转换始终成功,并按如下方式进行。
    • 如果源类型大于目标类型,则源值通过丢弃其“额外”最高有效位来截断。然后将结果视为目标类型的值。
    • 如果源类型小于目标类型,则源值是符号扩展的或零扩展的,因此它与目标类型的大小相同。如果源类型已签名,则使用符号扩展;如果源类型是无符号的,则使用零扩展。然后将结果视为目标类型的值。
    • 如果源类型与目标类型的大小相同,则源值被视为目标类型的值。
于 2011-09-27T21:11:43.370 回答
4

这取决于; 在一个checked上下文中,你会得到一个很大的异常;在unchecked上下文(默认)中,您可以保留最后一个字节的数据,就像您这样做一样:

byte b = (byte)(value & 255);
于 2011-09-27T21:12:01.973 回答
3

在您的特定情况下,当您查看值的位时,行为非常简单:

short myShort = 0x5D8C; // 23948
byte myByte = (byte)myShort; // myShort & 0xFF

Console.WriteLine("0x{0:X}", myByte); // 0x8C or 140
于 2011-09-27T21:08:51.847 回答
1

仅保留最后 8 位。二进制的 23948 是 101110110001100b。最后 8 位是 10001100b,等于 140。

于 2011-09-27T21:08:47.607 回答
1

当您将整数类型转换为“较小”的整数类型时,只考虑较小的权重位。从数学上讲,就好像您使用了模运算一样。所以你得到值 140 因为 23948 模 256 是 140。

将 long 转换为 int 将使用相同的机制。

于 2011-09-27T21:08:53.517 回答
1

当你这样做时,结果是一样的:

byte myByte = (byte)(myShort & 0xFF);

八位以上的一切都被简单地丢弃了。23948 (0x5D8C) 的低八位是 140 (0x8C)。

于 2011-09-27T21:09:17.640 回答
1

嗯...因为当您将短(2 个字节)转换为字节(1 个字节)时,它只获得第一个字节,并且 23948 的第一个字节代表 140。

于 2011-09-27T21:09:54.983 回答
1

23948 % 256 = 140,转换后最高有效字节丢失,所以输出为140

于 2011-09-27T21:10:12.377 回答
1

这就像当你有一个两位数“97”,并将其转换为一位数时,你失去了 9,只保留了“7”

于 2011-09-27T21:10:20.667 回答