关于运算符:c#两字节变量上的 xor在没有强制转换的情况下无法编译

C# XOR on two byte variables will not compile without a cast

本问题已经有最佳答案,请猛点这里访问。

下面为什么会引发编译时错误:"无法将类型"int"隐式转换为"byte":

1
2
3
4
        byte a = 25;
        byte b = 60;

        byte c = a ^ b;

如果我使用算术运算符,这是有意义的,因为A+B的结果可能比存储在单个字节中的结果大。

然而,将此应用于XOR运算符是毫无意义的。这里是一个永远不会溢出字节的位操作。

使用围绕两个操作数的强制转换可以:

1
byte c = (byte)(a ^ b);


我不能给你理由,但我可以从编译器必须遵循的规则(这可能不是你真正感兴趣的知识)的角度来解释为什么编译器有这种行为。

从C规范的旧版本(我可能会下载一个更新的版本)中,Emphasis补充道:

14.2.6.2 Binary numeric promotions This clause is informative.

Binary numeric promotion occurs for
the operands of the predefined +, ?,
*, /, %, &, |, ^, ==, !=, >, <, >=, and <= binary operators. Binary
numeric promotion implicitly converts
both operands to a common type which,
in case of the non-relational
operators, also becomes the result
type of the operation. Binary numeric
promotion consists of applying the
following rules, in the order they
appear here:

  • If either operand is of type decimal, the other operand is
    converted to type decimal, or a
    compile-time error occurs if the other
    operand is of type float or double.
  • Otherwise, if either operand is of type double, the other operand is
    converted to type double.
  • Otherwise, if either operand is of type float, the other operand is
    converted to type float.
  • Otherwise, if either operand is of type ulong, the other operand is
    converted to type ulong, or a
    compile-time error occurs if the other
    operand is of type sbyte, short, int,
    or long.
  • Otherwise, if either operand is of type long, the other operand is
    converted to type long.
  • Otherwise, if either operand is of type uint and the other operand is of
    type sbyte, short, or int, both
    operands are converted to type long.
  • Otherwise, if either operand is of type uint, the other operand is
    converted to type uint.
  • Otherwise, both operands are converted to type int.

因此,对于这些运算符,基本上小于int的操作数将转换为int(对于非关系操作,结果将是int)。

我说我不能给你一个理由;但是,我会猜一个——我认为C的设计者想要确保如果缩小的话可能会丢失信息的操作需要由程序员以强制转换的形式显式的缩小操作。例如:

1
2
3
4
byte a = 200;
byte b = 100;

byte c = a + b;  // value would be truncated

虽然在两个字节操作数之间执行异或操作时不会发生这种截断,但我认为语言设计者可能不希望有一组更复杂的规则,其中一些操作需要显式的强制转换,而另一些则不需要。

只是一个小提示:上面的引用是"信息性的"而不是"规范性的",但是它以易于阅读的形式涵盖了所有的案例。严格地说(从规范意义上讲),^运算符的这种行为是因为在处理byte操作数时,该运算符最近的重载是(从14.10.1"整数逻辑运算符"):

1
int operator ^(int x, int y);

因此,正如本文所解释的,操作数被提升到int,并产生int结果。


微软的半神程序员有一个答案:http://blogs.msdn.com/oldnewthing/archive/2004/03/10/87247.aspx

也许这更多的是关于编译器的设计。它们通过归纳编译过程使编译器更简单,它不必查看操作数的运算符,因此它将位操作集中在与算术运算符相同的类别中。因此,在类型加宽的情况下


我猜是因为操作符xor是为布尔值和整数定义的。

将整数结果转换为字节的结果是一种信息丢失转换,因此需要显式转换(程序员的nod)。


为什么两个字节必须转换成整数才能执行XOR?

如果您想深入研究它,cli规范(分区i)的12.1.2描述了这样一个事实:在评估堆栈上,只能存在int或long。在评估过程中,所有较短的积分类型都必须扩展。

不幸的是,我找不到直接指向cli规范的合适链接-我有一个本地的PDF副本,但不记得从哪里得到的。


这似乎是因为在C语言规范中,它是为整型和长型定义的http://msdn.microsoft.com/en-us/library/aa691307%28v=vs.71%29.aspx

因此,实际发生的情况是编译器将字节操作数隐式地强制转换为int,因为这样不会丢失数据。但如果不丢失数据(隐式地),则无法向下转换结果(int)。所以,您需要明确地告诉编译器您知道自己在做什么!


我想我记得一个关于这个的流行问题。

字节+字节=整数…为什么?


这与cli规范中有关隐式和显式强制转换的规则有关。整数(int=system.int32=4字节)比字节(显然是1字节)宽。因此,从int到byte的任何转换都可能是一个收缩转换。因此,编译器希望您将其显式化。


FWW字节A=25;字节B=60;a= a^ b;不工作。然而字节A=25;字节B=60;a^=B;工作。