C#字节相加操作
本文关键字:操作 字节 | 更新日期: 2023-09-27 18:26:02
有人能告诉我为什么在这里吗:
Byte b = 100;
b = (Byte)(b+200);
我必须使用显式类型转换。但是这里
Byte b = 100;
b += 200;
我不需要这么做?
编译器为这两种情况生成不同的IL代码吗?哪种情况更好?
因为标准允许(见下面的第二种情况):
14.14.2复合转让
形式为
x
op=
y
的运算通过应用二进制运算符重载解析(§14.2.4)进行处理,就好像该运算被写入x
opy
一样。然后,
如果所选运算符的返回类型可隐式转换为
x
的类型,则运算将求值为x = x
opy
,但x
只求值一次。否则,如果所选运算符是预定义运算符,如果所选择运算符的返回类型显式地可转换为
x
的类型,并且如果y
隐式地可转变为x
的类型,或者运算符是移位运算符,则运算被评估为x = (T)(x
opy)
,其中T
是x
的类型,除了CCD_ 17仅被评估一次之外。否则,复合赋值无效,并发生编译时错误。
在这种情况下,IL代码应该基本相同。当然,如果评估b
有副作用,在b = (byte)b + 200
的情况下会评估两次,在使用复合赋值时只评估一次。
这是C#标签中的常见问题解答,很难找到重复项。演员阵容的需求首先是相关的。根本原因是CLI仅为Opcodes.Add IL指令指定数量有限的有效类型。仅支持Int32、Int64、Single、Double和IntPtr类型的操作数。IntPtr也很特殊,C#语言禁止使用它。
因此,C#编译器让使用隐式转换将字节提升到运算符支持的类型。它将选择Int32作为最接近的兼容类型。加法运算的结果是Int32。如果不截断结果,丢弃多余的位,则无法将其放回字节。一个明显的例子是255+1,结果在Int32中为256,但不适合Byte,存储时产生0。
这是一个问题,语言设计者不希望在你没有明确承认自己意识到后果的情况下进行截断。需要进行强制转换以使编译器相信您知道。当然,有点逃避,你倾向于机械地制作演员阵容,而没有太多考虑后果。但这就是你的问题,而不是微软的:)
难点是+=运算符,这是一个非常好的编写压缩代码的运算符。类似于var关键字的简洁性。岩石和坚硬的地方,然而,你把演员阵容放在哪里?它就是不起作用,所以他们抛出了这个问题,并允许在没有强制转换的情况下进行截断。
值得注意的是VB.NET的工作方式,它不需要强制转换。但它提供了C#默认情况下不提供的保证,当结果不合适时,它会生成OverflowException。很不错,但那张支票不是免费的。
设计干净的语言是一个非常困难的问题。C#团队做得很好,尽管有缺点。否则就是处理器设计带来的缺点。IL有这些类型限制,因为这也是真正的32位处理器所具有的,尤其是90年代流行的RISC设计。它们的内部寄存器只能处理32位整数和IEEE-754浮点。并且只允许装载和存储较小的类型。Intel x86内核非常流行,实际上允许对较小类型进行基本操作。但这主要是一个历史事故,因为英特尔在8位8080和16位8086代中保持了设计兼容性。它不是免费的,16位操作需要额外的cpu周期。要避免。
规范将其称为复合赋值运算符的特定情况:
http://msdn.microsoft.com/en-us/library/aa691316%28v=vs.71%29.aspx
具体来说,项目符号2:
- 否则,如果所选运算符是预定义运算符,如果所选运算符的返回类型可显式转换为类型,并且如果y隐式地可转换为x的类型,那么运算计算为x=(T)(x运算y),其中T是x、 除了x仅被评估一次之外
上面的第二条规则允许x op=y被评估为x=(T)(x opy) 在某些情况下。该规则的存在使得预定义的当左操作数为类型为sbyte、byte、short、ushort或char。即使两个论点属于其中一种类型,则预定义的运算符会产生一个结果int型,如第7.2.6.2节所述。因此,没有铸造将不可能将结果分配给左操作数。
这是因为隐含的转换规则。
当您使用二进制+
运算符时,结果将转换为两种类型中较大的一种。文字200
是int类型,因此表达式b+200
的类型是int。赋值运算符=
不进行隐式转换,而是抛出错误。如
int x = 10;
Byte b = x; //Error
在第二种情况下,+=
运算符需要字节,因此200(类型为int,但适合字节)被隐式转换为字节,因为编译器知道它可以。以下内容不会编译,因为编译器不知道x是否适合一个字节。
Byte b = 100;
int x = 200;
b += x; //Error
如果你把x设为常量,那么它会编译:
Byte b = 100;
const int x = 200;
b += x; //OK