为啥短原语有赋值运算符(&=、+=)但没有非赋值运算符(&、+)? [复制]

Posted

技术标签:

【中文标题】为啥短原语有赋值运算符(&=、+=)但没有非赋值运算符(&、+)? [复制]【英文标题】:Why are there assignment operators (&=, +=) but no non-assignment operators (&, +) for short primitives? [duplicate]为什么短原语有赋值运算符(&=、+=)但没有非赋值运算符(&、+)? [复制] 【发布时间】:2015-12-14 02:49:54 【问题描述】:

我偶然发现在小于 32 位的原始类型上不允许按位或算术运算的行为,但实际上允许进行相应的赋值操作:

short BitwiseAnd(short a, short b)  return a & b;          // error
short BitwiseAndAssignment(ref short a, short b)  a &= b;  // works

short Add(short a, short b)  return a + b;                 // error
short AddAssignment(ref short a, short b)  a += b;         // works

同样的行为也适用于其他短基元类型,例如 bytesbyteushort

我了解算术和逻辑运算是为 32 位和更大的类型(intlong...)定义的,因为它是处理器提供的(see this question),并且更短的类型被扩展并且可以被转换回 8 或 16 位。但是,这是否有理由在赋值运算符中起作用?首先,我假设在幕后,shorts 被强制转换为int,但随后您将有一个赋值/返回值short value = (some int),这应该会产生错误,因为强制转换不是隐式的。

另一种说法:我在 Visual Studio 的即时窗口中尝试了一些代码,但似乎还有更多代码可以工作。即时窗口可能会进行一些通常是显式的隐式转换。例如,short a = (int)5; 允许在即时窗口中使用。所以这没有帮助。

【问题讨论】:

short Add(short a, short b) return (short)(a + b); ***.com/questions/4343624/… re short a = (int)5; 在即时窗口中 - 也适用于常规 C#;这里的值5(int)5 可以在编译时作为常量表达式完全处理和理解;编译器检查这些常量表达式是否溢出等,并允许它。相反,如果您执行short a = (int)50000000;,编译器会在编译时(而不是运行时)中断CS0031。 我明白了,谢谢!我没有注意到编译时常量替换。它只是因为语法上下文而有所不同,这使它在即时窗口中起作用,但在我的实际代码中不起作用(因为它不能被那里的常量表达式替换)。 【参考方案1】:

真正的错误是由于在对它们进行操作时将较小的整数类型隐式转换为int

当您有 a & b 其中 abshorts 时,它们都被转换为 int 并且 & 运算符适用,结果将是 int 类型,所以你不能在您的方法声明中将int 作为short 返回。一个简单的演员将解决这个问题。 (short)(a & b).

short BitwiseAnd(short a, short b)  return (short)(a & b);   //no error!

当你有

short BitwiseAndAssignment(ref short a, short b)  a &= b; 

编译器会为你生成转换,否则你不能在比int更小的类型上使用这些类型的运算符(+=*=、...)。


幕后发生了什么?

short a = 1;
short b = 2;

short c = a + b; //error! 

为什么?因为 + 运算符没有重载来接收两个 short 参数。由于存在shortint 之间的隐式转换,因此方法解析将选择具有两个int 作为输入参数的重载。因此它会将ab 转换为int然后调用返回int 的所选重载。因为它返回一个int,所以你不能将它存储在short 变量中,所以你需要明确地转换它。

short c = (short)(a + b)//this will work

【讨论】:

啊,感谢您的回答,我理解了 Marc 关于上述不可用语法的回答。谢谢!【参考方案2】:

但是,这是否有理由在赋值运算符中起作用?

是的:因为否则赋值运算符永远不会对这些类型起作用 - 不会有任何语法允许它起作用。 a += ba &= b期望很明确,所以自动进行转换。

使用a + ba & b,正如您已经注意到的:这是出于性能原因而扩大的;存在将其放回原处的语法,特别是 (short)(a+b) 等。

【讨论】:

你能扩展一下这个expectation的东西吗?因为按照我的预期,当 + 运算符未定义时,我肯定不会假设 += 已定义。所以我会期望没有语法可以让它工作。 @hschmauder 在 C# 中,赋值运算符不能显式重载;它们使用二元运算符隐式重载。含义:如果支持+,那么+=也支持,解释为a += b; => a = (AType)(a + b); “出于性能原因加宽”对我来说似乎是一个可疑的说法。我怀疑影响是否很大,尤其是因为 JITter 在许多情况下可以透明地扩大。

以上是关于为啥短原语有赋值运算符(&=、+=)但没有非赋值运算符(&、+)? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Java 没有条件与和条件或运算符的复合赋值版本? (&&=, ||=)

在C语言中能否直接给指针指向的数据赋值?为啥?

为啥移动赋值运算符应该返回对 *this 的引用 [重复]

为啥 ~= 在 C++ 中缺少唯一的非逻辑赋值运算符? [关闭]

为啥析取赋值运算符 |= 不适用于布尔向量?

为啥赋值运算符可以在 Rust 中被链接?