为什么编译器不将两个字面量提升为长整型而不是报错?

3
以下两个语句将导致编译器溢出错误(原因是常量表达式默认会检查溢出):
int i=(int)(int.MaxValue+100); // error
long l=(long)(int.MaxValue+100); // error

但是,如果编译器能够确定将这两个值相加会导致溢出,为什么它不将int.MaxValue100促升为long,然后再尝试将它们加在一起呢?据我所知,这应该不是问题,因为根据以下引用,整数字面量也可以是long类型:

当整数字面量没有后缀时, 它的类型是这些类型中的第一个 其中它的值可以被表示:int、uint、long、ulong。

谢谢。

你是指那个100吗?根据这个规则,它将始终是“int”(除非您添加后缀),因为这是第一个有效的类型。 - Rup
6个回答

10
文字字面值100可以表示为int,这是那四种类型中的第一个,因此它被视为int

int.MaxValue不是文字字面值。它是类型为int的公共常量字段。

因此,加法操作是int + int,它的结果是int,在这种情况下会溢出。

要将文字字面量100转换为long以进行长整数加法,请在其后缀中添加L

long l = int.MaxValue + 100L;

7
规则如下:
  • int + int 的结果是 int,而不是 long
  • 对于常量进行算术运算的默认值是“checked”;对于非常量进行算术运算的默认值是“unchecked”
  • 100 和 int.MaxValue 是常量

因此,根据规范,正确的行为应该在编译时进行溢出检查并报告错误。

如果您反而说:

int x = 100;
int y = int.MaxValue;
long z = x + y;

如果您想进行整数加法运算,正确的做法是对两个整数进行未经检查的加法运算,在溢出时进行包装,然后将结果转换为长整型。

如果您需要长整数算术运算,则必须明确指出。将操作数之一转换为长整型。


我猜您是C#开发团队的成员?不管怎样,我的问题更多的是为什么会做出这样的设计决策,而不是编译器如何处理它。 - user702769
4
@user702769说:“我同意。这些设计原则很简单:(1)C#是一种静态类型语言,(2)绝大多数整数算术运算都不接近域的边界,(3)该语言旨在识别可能是错误或歧义的模式并通知开发人员,而不是试图为开发人员选择并做出令人惊讶的错误选择。” - Eric Lippert

4
原因在于顺序。如果您阅读代码,它执行的操作是:使用值为MAX的int变量,并将100加到它上面。这在两种情况下都是正确的,这是在任何其他操作发生之前将被执行的代码。
如果您想使其工作,请执行以下操作:
long l = ((long)int.MaxValue)+100;

3

编译器不应根据运行时表达式的结果来提升类型。

int.MaxValue100都是整数。如果编译器根据表达式的结果更改类型,可能会出现问题。


3
简短的回答是,我想是因为它没有被设计成这样。每当微软向C#编译器(或任何人向任何东西添加功能时),都必须进行成本效益分析。人们必须想要该功能,并且实现该功能的成本(以编码和测试时间以及可能实现的其他功能的机会成本为代价)必须超过该功能对开发人员提供的潜在收益。
在您的情况下,让编译器按您的意愿操作的方法是简单、明显和清晰的。如果他们添加:
推断仅由常量和字面值组成的数字表达式的类型为包含结果值的最小类型
这意味着他们现在有更多的代码路径要检查和更多的单元测试要编写。改变预期的行为还意味着可能有人依赖于这个记录下来的事实,而他们的代码现在将无效,因为推断可能是不同的。

1

嗯,你期望什么呢?你正在说int.MaxValue+100,这超过了允许的integer最大值!要使其适用于long,请执行以下操作:

((long)(int.MaxValue)) + 100;

不要假定编译器会自动将值提升为long。那将更奇怪。

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