哪种方法可以在乘法时测试有符号整数溢出? [英] Which way to test for signed integer overflow on multiply?

查看:103
本文介绍了哪种方法可以在乘法时测试有符号整数溢出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下哪一项以符合标准的方式进行正确的事情"?您可以假定 m n 的类型为 int (带符号整数).主要问题是有符号整数溢出.

Which if any of the following does "the right thing" in a standards-compliant manner? You can assume that m and n are of type int (signed integer). The main issue is signed integer overflow.

示例1.

size_t bytes = n * m;
if (n > 0 && m > 0 && SIZE_MAX/n >= m) {
    /* allocate "bytes" space */
}

示例2.

if (n > 0 && m > 0 && SIZE_MAX/n >= m) {
    size_t bytes = n * m;
    /* allocate "bytes" space */
}

示例3.

if (n > 0 && m > 0 && SIZE_MAX/n >= m) {
    size_t bytes = (size_t)n * (size_t)m;
    /* allocate "bytes" space */
}

我认为它们全都错了,但并非都是出于相同的原因.那么什么是正确的?

I think they're all wrong, but not all for the same reason. So what would be correct?

这些摘录摘自此处.

经过编辑以强调主要问题是将带符号的整数相乘,这可能导致未定义的行为(无符号的行为则不会).

Edited to emphasise that the main issue is multiplying signed integers, which can lead to Undefined Behaviour (which unsigned does not).

我现在认为,只要整数,有符号整数,size_t和SIZE_MAX具有常规"值,或者至少符合相关标准,那么最后一个示例就可以正常工作.

I now think that the last sample works correctly provided that integer, signed integer, size_t and SIZE_MAX have the "usual" values, or at least that they comply with relevant standards.

推荐答案

示例1不正确,因为 m * n 的乘法可能超出有符号整数类型的可表示值范围,即导致不确定的行为.参见n1570 S6.5/5:

Sample 1 is incorrect, because the multiplication of m * n may exceed the range of representable values for the signed integer type, which leads to Undefined Behaviour. See n1570 S6.5/5:

如果在表达式的求值过程中发生异常情况(即,如果结果未在数学上定义,或者不在其可表示的值范围内类型),行为是不确定的.

If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.

这具有实际意义,因为允许编译器执行的其中一项操作是假定未发生未定义行为,并且可以使用它来优化代码,从而使 if 语句消失,没有任何作用.

This is of practical importance since one of the things the compiler is permitted to do is to assume that Undefined Behaviour has not happened, and it may use this to optimise the code so that the if statement disappears and is of no effect.

请注意,这仅适用于签名类型.无符号算术不会溢出.参见n1570 S6.2.5/9.

Note that this applies only to the signed type. Unsigned arithmetic does not overflow. See n1570 S6.2.5/9.

涉及无符号操作数的计算永远不会溢出,因为无法用结果无符号整数类型表示的结果是减少模数,该数比可以为最大值的最大值大一由结果类型表示.

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

样本2是不正确的,因为 m * n 的乘法被评估为有符号整数表达式,这可能再次导致未定义的行为.但是,在这种情况下,产生实际效果的可能性较小.结果很可能会产生正确的按位结果,并且一旦转换为无符号值,该值就很可能是正确的.该示例是错误的,但至少对于32位处理器而言更好.

Sample 2 is incorrect, because the multiplication of m * n is evaluated as a signed integer expression, which may again result in Undefined Behaviour. However in this case there is less likelihood of a practical effect. The result will most likely produce the correct bit-wise result and once cast to an unsigned the value is likely to be correct. The sample is wrong, but better, at least for 32 bit processors.

如果 unsigned int size_t 的大小与通常用于32位处理器的大小相同,则上述参数为true.当 size_t 大于 unsigned int 时,示例2将无法正常工作,因为通常在64位处理器上使用.有符号的乘法将溢出,并且对于某些值会产生错误的行为.

The above para will be true if unsigned int and size_t are the same size, as they usually are for 32 bit processors. Sample 2 will not work correctly where size_t is larger than unsigned int, as it usually is on 64 bit processors. The signed multiply will overflow and produce wrong behaviour for some values.

样本3几乎可以肯定是正确的.通过将 m * n 的乘积评估为无符号整数表达式,就不可能出现不确定的行为.[正如另一个答案所指出的,实际上只需要一个强制转换操作.]

Sample 3 is almost certainly correct. With the multiplication of m * n evaluated as an unsigned integer expression, there is no possibility of Undefined Behaviour. [As noted in another answer, only one cast operation is actually required.]

此处的确切行为取决于 int unsigned int size_t SIZE_MAX 的定义..通常的假设是 size_t unsigned int (或更大)相同,并且 SIZE_MAX 是一个无符号整数文字,但是这些是不是实际的要求.实际上, SIZE_MAX 仅需要至少为 65535 .至少需要 size_t 进行签名.

The exact behaviour here is subtly dependent on the definitions of int, unsigned int, size_t and SIZE_MAX. The usual assumption is that size_t is the same as unsigned int (or perhaps larger) and that SIZE_MAX is an unsigned integer literal, but these are not actually requirements. Indeed, SIZE_MAX is only required to be at least 65535. At least size_t is required to be unsigned.

由于我无法为它们找到任何可能导致样本失败的合理(甚至不可信)定义,因此我说样本3正常工作.

Since I have not been able to find any plausible (or even implausible) definitions for them that would cause the sample to fail, on that basis I say that Sample 3 works correctly.

这篇关于哪种方法可以在乘法时测试有符号整数溢出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆