为什么字节会结转
本文关键字:字节 为什么 | 更新日期: 2023-09-27 18:32:54
我最近一直在玩一些字节数组(处理灰度图像(。字节的值可以是 0-255。我正在修改字节,遇到了我分配给字节的值超出字节范围的情况。它对我正在玩的图像做了意想不到的事情。
我写了一个测试,并了解到字节会延续。例:
private static int SetByte(int y)
{
return y;
}
.....
byte x = (byte) SetByte(-4);
Console.WriteLine(x);
//output is 252
有结转!当我们反其道而行之时,也会发生这种情况。
byte x = (byte) SetByte(259);
Console.WriteLine(x);
//output is 3
我本来希望它在第一种情况下将其设置为 255,在第二种情况下设置为 0。 这种结转的目的是什么?仅仅是因为我正在转换这个整数赋值吗?这在现实世界中什么时候有用?
byte x = (byte) SetByte(259);
Console.WriteLine(x);
//output is 3
SetByte 结果的强制转换将模 256 应用于整数输入,从而有效地删除字节范围之外的位。
259 % 256 = 3
原因:实施者选择只考虑 8 个最低有效位,忽略其余位。
编译 C# 时,可以指定是在选中还是未选中模式下编译程序集(默认为未选中(。您还可以通过使用 checked
或 unchecked
关键字使代码的某些部分显式化。
您当前正在使用unchecked
忽略算术溢出并截断值的模式。checked
模式将检查可能的溢出,如果遇到溢出,则会抛出。
请尝试以下操作:
int y = 259;
byte x = checked((byte)y);
你会看到它抛出了一个OverflowException
.
unchecked
模式下的行为是截断而不是钳位的原因主要是出于性能原因,每个未经检查的强制转换都需要条件逻辑来钳制值,而大多数时候它是不必要的,并且可以手动完成。
另一个原因是,夹紧会导致数据丢失,这可能是不希望的。我不容忍以下代码,但已经看到了它(请参阅此答案(:
int input = 259;
var firstByte = (byte)input;
var secondByte = (byte)(input >> 8);
int reconstructed = (int)firstByte + (secondByte << 8);
Assert.AreEqual(reconstructed, input);
如果firstByte
不是 3 个,这根本行不通。
我最常依赖数字结转的地方之一是在实现GetHashCode()
时,请参阅Jon Skeet的覆盖System.Object.GetHashCode的最佳算法是什么答案。如果溢出意味着我们不得不Int32.MaxValue
,那么体面地实施GetHashCode
将是一场噩梦。
方法SetByte
是无关紧要的,简单地转换(byte) 259
也会导致3
,因为向下转换整数类型是作为字节的切割实现的。
您可以创建自定义钳位函数:
public static byte Clamp(int n) {
if(n <= 0) return 0;
if(n >= 256) return 255;
return (byte) n;
}
做算术模 2^n 使得不同方向的溢出错误可以相互抵消。
byte under = -12; // = 244
byte over = (byte) 260; // = 4
byte total = under + over;
Console.WriteLine(total); // prints 248, as intended
如果 .NET 反而溢出饱和,则上述程序将打印错误答案 255。
对于具有直接类型强制转换(使用 (byte)
时(的情况,边界控件不处于活动状态,以避免性能降低。
仅供参考,大多数具有字节操作数的操作的结果是整数,不包括位操作。使用 Convert.ToByte()
,您将获得溢出异常,您可以通过将 255 分配给目标来处理它。
或者你可以创建一个功能来做这个检查,正如下面的另一个人提到的。如果 perfomanse 是键,请尝试添加属性[MethodImpl(MethodImplOptions.AggressiveInlining)]
到那个功能。