11

我正在查看一个项目的源代码,我注意到以下语句(keyByte 和 codedByte 都是 type byte):

return (byte)(keyByte - codedByte);

我现在试图了解在 keyByte 小于 codedByte 的情况下会产生什么结果,这会导致负整数。

经过一些实验以了解强制转换具有 [-255 : -1] 范围内的值的负整数的结果,我得到以下结果:

byte result = (byte) (-6);  // result = 250
byte result = (byte) (-50); // result = 206
byte result = (byte) (-17); // result = 239
byte result = (byte) (-20); // result = 236

因此,只要-256 < a < 0,我能够通过以下方式确定结果:

result = 256 + a;

我的问题是:我应该总是期望这种情况吗?

4

5 回答 5

5

是的。请记住,.Net“字节”的域中没有“-”这样的东西:

http://msdn.microsoft.com/en-us/library/e2ayt412.aspx

因为 Byte 是无符号类型,所以不能表示负数。如果在计算结果为 Byte 类型的表达式上使用一元减号 (-) 运算符,Visual Basic 首先将表达式转换为 Short。(注意:用任何 CLR/.Net 语言替换“Visual Basic”)

附录:这是一个示例应用程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestByte
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = -255; i < 256; i++)
            {
                byte b = (byte)i;
                System.Console.WriteLine("i={0}, b={1}", i, b);
            }
        }
    }
}

这是结果输出:

testbyte|more
i=-255, b=1
i=-254, b=2
i=-253, b=3
i=-252, b=4
i=-251, b=5
...
i=-2, b=254
i=-1, b=255
i=0, b=0
i=1, b=1
...
i=254, b=254
i=255, b=255
于 2012-05-13T20:08:54.737 回答
5

是的,情况总是如此(即它不仅仅取决于您的环境或编译器,而是被定义为 C# 语言规范的一部分)。请参阅http://msdn.microsoft.com/en-us/library/aa691349(v=vs.71).aspx

unchecked上下文中,通过丢弃任何不适合目标类型的高位位来截断结果。

下一个问题是,如果你拿掉 -256 和 -1 之间的负数的高位int,并将其作为一个字节读取,你会得到什么?这就是你已经通过实验发现的:它是 256 + x。

请注意,字节序无关紧要,因为我们要丢弃高阶(或最高有效)位,而不是“第一个”24 位。因此,无论我们从哪一端获取它,我们都会留下构成该 int 的最低有效字节。

于 2012-05-13T20:33:53.230 回答
3

这是一个执行与转换为字节相同的逻辑的算法,以帮助您理解它:

对于阳性:

byte bNum = iNum % 256;

对于底片:

byte bNum = 256 + (iNum % 256);

这就像搜索任何k导致x + 255k在范围内的东西0 ... 255。只能有一个k产生具有该范围的结果,结果将是转换为字节的结果。

另一种看待它的方式就像它“围绕字节值范围循环”:

让我们iNum = -712再次使用,并定义一个bNum = 0.

我们将这样做iNum++; bNum--;直到iNum == 0

iNum = -712;
bNum = 0;

iNum++; // -711
bNum--; // 255 (cycles to the maximum value)

iNum++; // -710
bNum--; // 254

... // And so on, as if the iNum value is being *consumed* within the byte value range cycle.

当然,这只是一个说明,看看它是如何运作的。

于 2012-05-13T20:22:09.520 回答
0

这就是在unchecked上下文中发生的事情。您可以说运行时(或编译器,如果您在编译时Int32知道您转换的那个Byte)根据需要多次添加或减去 256,直到找到可表示的值。

checked上下文中,会导致异常(或编译时错误)。请参阅http://msdn.microsoft.com/en-us/library/khy08726.aspx

于 2012-05-13T20:20:18.647 回答
0

是的 - 除非你得到一个例外。

.NET 仅对 4 字节和更大的数据类型定义所有算术运算。所以唯一不明显的一点是如何将 a 转换int为 a byte

对于从一个整数类型到另一个整数类型的转换,转换的结果取决于溢出检查上下文(如 ECMA 334 标准,第 13.2.1 节)。

因此,在以下上下文中

checked
{
    return (byte)(keyByte - codedByte);
}

你会看到一个System.OverflowException. 而在以下情况下:

unchecked
{
    return (byte)(keyByte - codedByte);
}

无论您是否将 256 的倍数添加到差异中,您都可以确保始终看到您期望的结果;例如,2 - 255 = 3。

无论硬件如何 表示有符号值,这都是正确的。CLR 标准 (ECMA 335) 在第 12.1 节中指定Int32类型是“32 位二进制补码有符号值”。(嗯,这也匹配所有当前可用 .NET 或 mono 的平台,所以几乎可以猜到它无论如何都会工作,但很高兴知道这种做法受到语言标准的支持并且可移植。)

一些团队不想明确指定溢出检查上下文,因为他们有一个在开发周期早期检查溢出的策略,而不是在发布的代码中。在这些情况下,您可以像这样安全地进行字节算术:

return (byte)((keyByte - codedByte) % 256);
于 2012-05-13T20:20:32.743 回答