如何在C#中减去一行的字节数

Fli*_*ter 5 c# compiler-construction language-construct

这真的很奇怪.有谁能解释一下?

此代码不起作用:

const byte ASC_OFFSET = 96;
string Upright = "firefly";
byte c7 = (byte)Upright[6] - ASC_OFFSET;
//Cannot implicitly convert type 'int' to 'byte'.
Run Code Online (Sandbox Code Playgroud)

此代码也不起作用:

const byte ASC_OFFSET = 96;
string Upright = "firefly";
byte c7 = (byte)Upright[6] - (byte)ASC_OFFSET;
//Cannot implicitly convert type 'int' to 'byte'.
Run Code Online (Sandbox Code Playgroud)

然而,将减法放在一个单独的行上工作得很好:

const byte ASC_OFFSET = 96;
string Upright = "firefly";
byte c7 = (byte)Upright[6];
c7 -= ASC_OFFSET;
Run Code Online (Sandbox Code Playgroud)

我不介意将这些陈述分开,如果我必须......但我不得不怀疑......

为什么?

Sim*_*ier 7

这是因为1)byte操作导致int(见这里的原因:http://blogs.msdn.com/b/oldnewthing/archive/2004/03/10/87247.aspx)和2)以下C#代码

c7 -= ASC_OFFSET;
Run Code Online (Sandbox Code Playgroud)

将"神奇地"编译成幕后的场景

c7 = (byte)(c7 - ASC_OFFSET);
Run Code Online (Sandbox Code Playgroud)

这在C#规范中有详细记载:http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf

14.14.2复合赋值:

x op = y形式的操作通过应用二元运算符重载决策(第14.2.4节)来处理,就像操作是用x op y编写的一样.然后,

•如果所选运算符的返回类型可隐式转换为x的类型,则操作将计算为x = x op y,但x仅计算一次.

否则,如果所选运算符是预定义运算符,如果所选运算符的返回类型可明确转换为x类型,并且如果y可隐式转换为x类型或运算符是移位运算符,则操作被评估为x =(T)(x op y),其中T是x的类型,除了x仅被评估一次.

•否则,复合赋值无效,并发生编译时错误


Eri*_*ert 5

您的前两个示例无法编译的原因是:

  • 强制转换比减法结合“更紧密”。也就是说,“(C)de”表示“((C)d)-e”,而不是“(C)(de)”。强制转换运算符的优先级更高。
  • 因此,无论进行何种类型转换,减法的两个操作数的类型都是字节。
  • 减法的类型是 int,因为没有在字节上定义减法运算符。
  • 因此,您将 int 分配给字节而不进行强制转换,这是非法的。

字节上没有减法运算符,因为假设您有一个包含 7 的字节,并从中减去一个包含 8 的字节,您真的希望它成为字节 255 吗?我想大多数人会希望它是 int -1。

最后,你到底为什么要以字节为单位这样做?这没有任何意义。C# 中的字符不是字节;如果你想对字符进行算术那么为什么不从字符'y'中减去字符96而不是进行有损且危险的字节转换?

  • 更根本的是,这里的问题是您认为字节是数字的表示,在其上进行算术是明智的。这实际上并不是一种非常高效或有用的考虑字节的方式。与其将字节解释为数量,不如将其仅仅视为存储八位的便捷方式。如果您想操作*数字*,请使用为此设计的数据类型,即 int。 (3认同)
  • 编译器应该如何知道这一点? (2认同)

Meh*_*dad 4

我以前也注意到过这一点。我认为这是因为该-=运算符是为字节类型预定义的,而在前一种情况下,您实际上是将 an 放在inta 内byte,这是不允许的。他们这样做的原因不一定有意义,但它符合规则,因为在前一种情况下,编译器-在进行赋值时无法“偷看”运算符。

如果你确实需要在一行上进行减法,而不是说:

byte c7 = (byte)Upright[6] - ASC_OFFSET;
Run Code Online (Sandbox Code Playgroud)

说:

byte c7 = (byte)(Upright[6] - ASC_OFFSET);
Run Code Online (Sandbox Code Playgroud)