【问题标题】:C# 0 (minus) uint = unsigned result?C# 0(减号)uint = 无符号结果?
【发布时间】:2012-03-01 23:04:57
【问题描述】:
public void Foo(double d){
    // when called below, d == 2^32-1 
    ...
}
public void Bar(){
    uint ui = 1;
    Foo( 0 - ui );
}

我希望 0 和 ui 在这里都被提升为有符号的多头。

确实,使用 0 字面量,在编译时就可以知道强制转换为 uint 是安全的,

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

谢谢!

语言规范是否涵盖了这样的半模棱两可的情况?

【问题讨论】:

  • 这个问题等待 Jon Skeet :)

标签: c# operators


【解决方案1】:

为什么要升级为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)有点曲折,但我相信它定义明确,一点也不模棱两可。

如果困扰你的是溢出,你会期望 this 也会失败吗?

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

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

【讨论】:

  • 我认为他的问题更多在于(可能)模棱两可的结果值。即如果我从 0 中减去一个正数,我不应该得到一个肯定的结果。与您的 int 示例类似,将 10 添加到正数不应导致负数。我会问一个问题,如果您正在处理这些类型的数字界限,最好使用checked 来确保您的结果不模棱两可(至少对您来说模棱两可)
  • @NominSim:这里没有歧义。它的行为完全符合规范的要求。如果 OP 想要使用经过检查的上下文,那么他们绝对可以,但这里不需要警告,而且一切都正常。我相信 OP 的 actual 问题是它是使用 uint 算术执行的,而他希望它使用 long 算术:“我希望 0 和 ui 在这里都被提升为带符号的 long。 "
  • 我知道它的行为完全符合规范的规定,歧义不在规范中,而是在动作中,如果我从负数中减去保证的正数,我应该得到一个阴性结果。这就是为什么我认为 OP 在处理可能超出特定数据结构范围的数字时应该使用检查过的上下文。
  • @NominSim:明白它符合规范,但我不相信 OP 做到了。我认为“歧义”这个词在这里没有用——根本没有。可能会有意想不到或不受欢迎的行为,但这与模棱两可不同。
  • 是的,我在使用这个词,因为 OP 使用了它。现在我也想多了,他“至少应该发出警告”的说法起初对我来说似乎是合理的,但我越想越同意你的看法,手-持有只能让你到目前为止......
【解决方案2】:

int 强制转换为 uint 以执行从 0 的减法(编译器将其隐式解释为 uint)。请注意,intuint 是隐式转换,因此没有警告。您的代码没有任何问题...除了 uint 不是 CLS 兼容的。你可以阅读为什么here。在MSDN上了解更多关于 CLS 编译代码的信息

【讨论】:

  • intuint 通常不是隐式转换 - 这是一个隐式常量表达式转换。请参阅规范的第 6.1.9 节。如果我们从int 变量 开始,那么就会升级到long。 (intuint 都可以隐式转换为long。)
  • @JonSkeet 感谢您的澄清 :)
  • 接受这个答案是因为我感到困惑的根本原因只是零可以隐式转换为 uint。基于 0 是 int 的假设,我预计升职会长...
【解决方案3】:

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

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

从技术上讲,执行以下操作:

double d = checked(0-ui);

将导致System.OverflowException 的抛出,这可能是您所期望的,但根据规范,因为未检查此溢出未报告。

【讨论】:

    猜你喜欢
    • 2012-01-06
    • 1970-01-01
    • 1970-01-01
    • 2016-03-27
    • 2021-06-09
    • 1970-01-01
    • 2012-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多