出于某种原因,我根本不理解(或看到)为什么这样做:
UInt32 a = 0x000000FF;
a &= ~(UInt32)0x00000001;
但这不是:
UInt16 a = 0x00FF;
a &= ~(UInt16)0x0001;
它给出错误'常数值 - (某些数字)无法转换为UInt16'。有人可以解释为什么这是以及如何解决这个问题?
答案 0 :(得分:2)
按位否定将结果提升为int
,尽管是演员。你可以通过按位和按位求反的结果来解决这个问题,如下所示:~0x0001 & 0xFFFF
。
答案 1 :(得分:2)
因为标准§14.6.4(ISO 23270)说:
14.6.4按位补码运算符
对于
~x
形式的操作,一元运算符重载决策(第14.2.3节) 用于选择特定的运算符实现。操作数转换为 所选运算符的参数类型,结果的类型为 返回运算符的类型。预定义的按位补码运算符为:int operator ~(int x); uint operator ~(uint x); long operator ~(long x); ulong operator ~(ulong x);
对于每个运算符,运算结果是
x
的按位补码。
如果您通过§14.2.3中指定的一元运算符重载决策,您将发现,如§14.2.6.1(“一元数字促销”)所述,这是信息性的而不是规范性的,即网络效果是这样的:
对预定义
+
,–
和~
的操作数进行一元数字提升 一元运营商。一元数字促销只包括转换操作数 键入sbyte
,byte
,short
,ushort
或char
以输入int
。
所以尽管你的演员~(ushort)0x0001
,编译器足够聪明,可以注意常量表达式并执行常量折叠,这意味着最终结果是带符号的32位整数值-2或0xFFFFFFFE
。和...
由于表达式a &= b ;
完全等同于a = a & b ;
,因此您尝试按ushort
和int
进行按位AND。 ushort
向上转换为int,按位AND求值,产生带符号的32位整数结果。
。
。
。
无法分配给ushort
(无符号16位)。
这就是原因。
答案 2 :(得分:0)
您的表达式在编译时进行评估,结果检测到溢出错误并阻止编译。
下面的示例显示默认情况下运行时不会抛出异常:
UInt16 a = 0x00FF;
UInt16 b = 0x0001;
a &= (UInt16)~b;
请注意,您的代码也在转换int
(~
操作UInt16
转换为int
) - 所以我在投降前移动了~
为什么:C#编译器通常会尽可能地尝试阻止无意的代码行为,这与int
/ uint
/ long
/ ulong
上定义的所有按位操作相结合并且编译时间常量评估会导致此编译时错误。