强类型赋值和转换赋值有什么区别?

17

今天在编写代码时,我遇到了这个问题。以以下代码为例:

long valueCast  = (long)(10 + intVariable);
long valueTyped = 10L + intVariable;
这两者之间是否有任何区别,或者它们编译成完全相同的结果?有哪种约定比另一种更好吗?
所以我知道这不是一个关键性的问题(两个都能工作)。我只是非常好奇它们之间可能存在的差异! 编辑 - 修改了代码示例,使其更接近于我的原始情况。我想让问题更清楚,所以我用常量替换了变量。没意识到编译器会自动执行算术运算(从而改变了这个问题的答案)。

@Servy,收到。我本来想说话的,但是提问者将文字“2”更改为“intVariable”,使我的观点无效了。 - Frédéric Hamidi
作为对其他人的提示,我首先尝试引用 long 类型文档。虽然它没有解决我的问题,但它可能会帮助其他人。 - drew_w
1
我在我的最新文章中讨论了你的问题,关于算术陷阱,请参见此链接:http://devproconnections.com/development/c-sharp-code-writing-tips-eric-lippert-math - Eric Lippert
此外,“晚期提升”缺陷最常见于乘法运算,例如 long p = (long)(a * b * c * d * e);,而实际想要的是 long p = (long)a * b * c * d * e); - Eric Lippert
@drew_w:规范没有明确说明,但是在C#中,整数是二进制补码。 - Eric Lippert
显示剩余2条评论
3个回答

38

是的,这两者之间有很大的区别。虽然对于特定的值来说没有区别,但是使用不同的值进行完全相同的表达式会显示出差异。

在第一个版本中,加法是以32位算术方式执行的,然后将结果转换为long

在第二个版本中,第一个操作数已经是long类型的,所以第二个操作数被提升为long类型,然后进行64位算术运算。

当然,在这种情况下,编译器无论如何都会执行算术运算(并且在两种情况下得出相同的结论),但是理解转换操作的结果和转换操作的操作数之间的区别非常重要。

以下是一个例子:

unchecked
{
    long valueCast  = (long)(2000000000 + 2000000000);
    long valueTyped = 2000000000L + 2000000000;
    Console.WriteLine(valueCast);
    Console.WriteLine(valueTyped);
}

结果:

-294967296
4000000000

请注意,这必须在显式未经检查的上下文中完成,否则第一个加法甚至无法进行编译 - 您将收到“CS0220:在已检查模式下编译时操作溢出”的错误。


那么(long)10 + 2和10L + 2是等价的吗?(我真的有疑问) - user1162766
3
@Areks:是的,那些是等价的...虽然后者可以让你表达32位范围之外的常数。 翻译:是的,那些是等价的……尽管后者可以允许您表达32位范围之外的常量。 - Jon Skeet
2
谢谢Jon!我看着你的答案从零开始构建并投票,现在感觉可以毫无遗憾地离开了! - user1162766

7

好的,这是一个编译错误:

long valueCast = (long)(2147483647 + 2);

"

在严格模式下编译时操作溢出。

然而,这样做是可以正常工作的:

"
long valueTyped = (2147483647L + 2);

正如Jon Skeet所说,区别在于您是在求和之前还是之后将其转换为long


4
当然,就在我回答的时候,Jon编辑了基本相同的示例。 :) - Tim Goodman
@dev_feed 好吧,毕竟我们谈论的是Jon Skeet。 - Tim Goodman

2

在您的示例中,10L + 2等于((long)10) + 2;

这与(long)(10+2)不同,因为:

(long)(10+2)操作执行为int(32位),然后转换为long(64位)

((long)10) + 2;操作执行为long(64位),因为在实际操作之前,10被转换为long。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接