2012-03-01 40 views
4
public void Foo(double d){ 
    // when called below, d == 2^32-1 
    ... 
} 
public void Bar(){ 
    uint ui = 1; 
    Foo(0 - ui); 
} 

我希望在这里将0和ui都提升为有符号的longs。C#0(减号)uint =无符号结果?

真,用0字面是在编译的时候,强制转换为UINT安全可知,

但我想这一切似乎只是错误的。至少应该发出警告。

谢谢!

语言规范是否涵盖了这样的半含糊的情况?

+5

这个问题等待Jon Skeet :) – 2012-03-01 23:06:38

+2

不长:-) – 2012-03-01 23:11:46

回答

0

这就是int,它正被转换为uint以执行从0减去(这被编译器隐含地解释为uint)。请注意,intuint是一个隐式转换,因此没有警告。你的代码没有问题......除了uint不是CLS编译器。你可以阅读为什么here。有关CLS编译代码的更多信息MSDN

+1

'int'到'uint'通常不是一个隐式转换 - 这是一个*隐式常量表达式转换*。参见规范的6.1.9节。如果我们开始使用'int' *变量*,那么就会提升为'long'。 (两个'int'和'uint'可以隐式转换为'long'。) – 2012-03-01 23:20:47

+0

@JonSkeet感谢澄清:) – SiliconMind 2012-03-02 10:00:48

+0

接受这个答案,因为我的困惑的根本原因很简单,零隐式转换为uint。基于0是int的假设,我期望推广长... – mike 2012-03-06 22:18:43

7

为什么要提升到long?该规范(部分7.8.5)列出了四个操作为整数减法:

  • int operator-(int x, int y);
  • uint operator-(uint x, uint y);
  • long operator-(long x, long y);
  • ulong operator-(ulong x, ulong y);

鉴于恒定值0隐式转换为uint,但uintui而不是可以隐式转换为int,第二个运算符根据7.3.4节中描述的二元运算符重载分辨率步骤进行选择。

(难道你不知道有隐含的常量表达式转换从0uint,因此这是混乱的一部分吗?请参见C#4规格的细节部分6.1.9)

下一节7.3.4(然后参考7.3.5和7.5.3)稍微有些曲折,但我认为它是明确的,并且一点也不含糊。

如果这是溢出困扰你,预计这个也会失败?

int x = 10; 
int y = int.MaxValue - 5; 
int z = x + y; 

如果没有,什么是真正这里的区别?

+0

我认为他的问题更多的是(潜在)不明确的结果值。即如果我从0减去一个正数,我不应该得到一个积极的结果。与你的int例子类似,向正数加10不应该导致负数。如果你在处理数字上的这些类型的边界问题,我会遇到的一个问题是不是最好使用'checked'来确保你的结果不含糊不清(至少对你来说不明确) – NominSim 2012-03-01 23:29:58

+0

@NominSim:有这里没有歧义。它的行为*正如说明书规定的那样。如果OP想要使用checked context,那么他们绝对可以,但是这里不需要警告,并且它的行为都是正确的。我相信OP的* actual *问题在于它使用'uint'算术执行,而他期望它使用'long'算术:“我希望这里将0和ui提升为有符号长整数。” – 2012-03-02 00:06:23

+0

我知道它的行为完全符合规范要求,模糊不在规范中,而是在行为中,如果我从负数中减去保证的正数,我应该得到否定结果。这就是为什么我认为OP应该使用被检查的上下文,如果他们正在处理可能导致出于特定数据结构的边界的数字。 – NominSim 2012-03-02 13:41:19

0

在已检查的上下文中,如果差异超出结果类型的范围,则会引发System.OverflowException。在未检查的上下文中,不报告溢出,并且丢弃结果类型范围之外的任何重要的高位。

http://msdn.microsoft.com/en-us/library/aa691376(v=vs.71).aspx

技术上,执行以下操作:

double d = checked(0-ui); 

将导致System.OverflowException投掷这是你期望也许什么,而是根据规范,因为这是不检查溢出未报告。