相关疑难解决方法(0)

C#中具有未定义行为的代码

在C++中,有很多方法可以编写编译的代码,但会产生未定义的行为(维基百科).C#中有类似的东西吗?我们可以用编译的C#编写代码,但是有未定义的行为吗?

c# c++ undefined-behavior

50
推荐指数
4
解决办法
4080
查看次数

为什么定义C#规范(int.MinValue/-1)实现?

该表达式int.Minvalue / -1根据C#规范导致实现定义的行为:

7.8.2分部运营商

如果左操作数是最小的可表示的int或long值而右操作数是-1,则发生溢出.在已检查的上下文中,这会导致抛出System.ArithmeticException(或其子类).在未经检查的上下文中,它是实现定义的,是否抛出System.ArithmeticException(或其子类)或溢出未报告,结果值是左操作数的值.

测试程序:

var x = int.MinValue;
var y = -1;
Console.WriteLine(unchecked(x / y));
Run Code Online (Sandbox Code Playgroud)

这会引发OverflowException.NET 4.5 32位,但它没有.

为什么规范会保留结果实现定义?这是反对这样做的情况:

  1. idiv在这种情况下,x86 指令总是会导致异常.
  2. 在其他平台上,可能需要运行时检查来模拟此操作.但是与该部门的成本相比,该检查的成本会很低.整数除法非常昂贵(15-30个周期).
  3. 这会打开兼容性风险("写一次无处可写").
  4. 开发者惊喜.

同样有趣的是,如果x / y是一个编译时常量我们确实得到unchecked(int.MinValue / -1) == int.MinValue:

Console.WriteLine(unchecked(int.MinValue / -1)); //-2147483648
Run Code Online (Sandbox Code Playgroud)

这意味着,x / y可以有根据使用的语法形式在不同的行为(而不是只依赖于的值xy).这是规范允许的,但它似乎是一个不明智的选择.为什么C#这样设计?

一个类似的问题指出,在说明书这一确切行为被规定,但它并没有(足够的)回答为什么语言是这样设计的.不讨论替代选择.

c# language-design

24
推荐指数
2
解决办法
454
查看次数

为什么编译器会评估与运行时不同的余数MinValue%-1?

我认为这看起来像C#编译器中的一个错误.

考虑这段代码(在方法内):

const long dividend = long.MinValue;
const long divisor = -1L;
Console.WriteLine(dividend % divisor);
Run Code Online (Sandbox Code Playgroud)

它编译时没有错误(或警告).好像是一个bug.运行时,0在控制台上打印.

然后没有const,代码:

long dividend = long.MinValue;
long divisor = -1L;
Console.WriteLine(dividend % divisor);
Run Code Online (Sandbox Code Playgroud)

当它运行时,它正确地导致OverflowException被抛出.

C#语言规范专门提到了这个案例,并说System.OverflowException将抛出一个.它不依赖于上下文checkedunchecked似乎(也是与余数运算符的编译时常量操作数的错误与checked和相同unchecked).

int(System.Int32),而不仅仅是long(System.Int64)发生同样的错误.

相比之下,编译器处理dividend / divisorconst操作数比要好得多dividend % divisor.

我的问题:

我是对的,这是一个错误吗?如果是,它是一个众所周知的错误,他们不希望修复(因为向后兼容性,即使使用% -1编译时常量相当愚蠢-1)?或者我们应该报告它,以便他们可以在即将推出的C#编译器版本中修复它?

c# operators overflowexception compiler-bug modulus

22
推荐指数
1
解决办法
538
查看次数

地板整数除法

在 C# 中是否有一种简单、高效和正确(即不涉及到/从 double 转换)的方法来进行地板整数除法(例如Python 提供)。

换句话说,以下的有效版本,不会遭受长/双转换损失。

(long)(Math.Floor((double) a / b))
Run Code Online (Sandbox Code Playgroud)

还是必须自己实现它,例如

static long FlooredIntDiv(long a, long b)
{
    if (a < 0)
    {
        if (b > 0)
            return (a - b + 1) / b;
        // if (a == long.MinValue && b == -1) // see *) below
        //    throw new OverflowException();
    }
    else if (a > 0)
    {
        if (b < 0)
            return (a - b - 1) / b;
    }
    return a / …
Run Code Online (Sandbox Code Playgroud)

.net c# math integer-arithmetic

7
推荐指数
1
解决办法
8062
查看次数

未经检查的 C# 块中的 System.OverflowException

如果我将 Int32.MinValue 和 -1 传递到Divide()方法中,System.OverflowException尽管块发生在unchecked块中,我还是得到 a 。

    private static int Divide(int n, int d)
    {
        return unchecked (n / d);
    }
Run Code Online (Sandbox Code Playgroud)

这让我感到惊讶 - 除非我错误地阅读了已检查/未检查的文档,否则我希望它只会给我一个溢出的输出(因为 Int32.MinValue / -1 = 2^31 = Int32.MaxValue + 1,我期待溢出到 Int32.MinValue 的值)。相反,它抛出了一个OverflowException.

这是一个显示问题的DotNetFiddle

c# unchecked

6
推荐指数
1
解决办法
62
查看次数

如何在整数除法上停止抛出OverflowException?

我得到OverflowException异常的扔给我时,我不希望他们(或因此我认为).我正在执行一些奇怪的计算,我希望值溢出,丢弃溢出的位.看来我不能让这个工作正常.基本上这是一对i和j,当我迭代大集合(int.MinValue到int.MaxValue)时发生.

// i and j are ints
// i is -2147483648
// j is -1
var x = i / j;

// I also tried using unchecked keyword, but it doesn't help    
var x = unchecked(i / j);
Run Code Online (Sandbox Code Playgroud)

更新:

预期的数学值-2147483648/-1是2147483648.但是,这个特定的代码并没有真正尝试找到这个数字.这是一系列比特操纵事情的一部分,有点难以理解.说实话,我甚至不知道自己的目的是什么,因为我没有真正记录这个方法,而且只需要一天时间就可以在我脑海中引发严重的WTF泡沫.所有我知道它的工作原理与设计用于处理案例的特殊代码.

关于预期价值:

因为int只能保持2147483647的最大值,所以我希望丢弃溢出值Y值.

如果我对此有所了解,那么对于模糊方法来说,这可能是文档的重要性.

.net c# math overflowexception

2
推荐指数
1
解决办法
2914
查看次数