检测整数溢出

Cor*_*Xii 8 int d

如何检测D中的整数溢出?(检查携带标志?)

原始示例:

ubyte a = 100;
ubyte b = 200;
ubyte c = a + b;
// c can't represent 300; how to detect the overflow now?
Run Code Online (Sandbox Code Playgroud)

修改后的例子:

uint a = 2_000_000_000;
uint b = 3_000_000_000;
uint c = a + b;
// c can't represent 5_000_000_000; how to detect the overflow now?
Run Code Online (Sandbox Code Playgroud)

还有乘法和前/后增量.

Jon*_*vis 9

对于初学者来说,你提供的代码甚至都不会编译,因为大小小于的所有整数数学都是用来int完成的int.因此,结果a + bint,并且int不会隐式转换为ubyte,因为这是一个缩小的转换.如果你想分配它c,那么你需要投射它.

ubyte c = cast(ubyte)(a + b);
Run Code Online (Sandbox Code Playgroud)

现在,这显然是一个未经检查的转换,它会很高兴的东西44c(因为这是给定的值塑像的结果100200).如果您想要检查转换,请使用std.conv.to:

ubyte c = to!ubyte(a + b);
Run Code Online (Sandbox Code Playgroud)

这将抛出一个ConvOverflowException(它的子类ConvException),因为结果将不适合所请求的类型.

如果你想自己进行投射,然后检查是否有溢出,那么你基本上和C/C++一样,并且没有进位标志或任何类似的东西.如果您使用汇编代码检查,可能存在这种情况.我不知道.但是这种语言肯定不会提供类似的东西.std.conv.to通过检查结果并查看它是否太大或太小(取决于参数的符号和类型)来计算出来.


Ada*_*ppe 7

您可以使用一些内联汇编轻松检查它:

asm { jo overflowed; } // for checking signed types
// or
asm { jc overflowed; } // use this for checking unsigned types

/* continue going */

return;

overflowed:

/* do whatever to handle it */
Run Code Online (Sandbox Code Playgroud)

注意:您可能无法将其放入函数中,因为调用该函数可以重置该标志.您希望在您感兴趣的操作之后立即将其放入内联.

可以创建一个使用运算符重载的类型来抛出溢出:http: //arsdnet.net/dcode/ranged.d就是一个例子.或者我认为标准库中的模块是std.bigint,通过提供任意大的整数类型来避免溢出.

  • 是的......虽然注意溢出并不是真的发生在unsigneds上.考虑-1:11111111的二进制表示(为简洁起见,使用ubyte).这与255相同.但是处理器不知道或不关心类型是否已签名,它只是看到了数字.255 + 1 == -1 + 1 == 0.这样就会设置进位标志,但不会设置溢出标志.因此,如果您专门使用无符号数字,则需要jc指令 - 如果是携带则跳转 - 而不是. (4认同)
  • 另一个潜在的问题是增量指令不*设置进位标志....如果在编译时已知一个,则编译器将优化+ = 1到inc a.所以你对a + b没问题,因为那些是运行时,但是+ = 1或者+ ++可能会给asm检查带来惊人的传递. (2认同)