【问题标题】:What is the result of 'wrapping' a multiplication overflow?“包装”乘法溢出的结果是什么?
【发布时间】:2017-06-01 09:42:34
【问题描述】:

bcache 源 here 包含以下行:

schedule_delayed_work(&dc->writeback_rate_update,
    dc->writeback_rate_update_seconds * HZ);

writeback_rate_update_seconds 定义为 unsigned int,在 x86_64 上是 appears to be 32 bit,我不确定 HZ 有什么类型,但我相信值是 1000,并假设它是 32 位或更少。

如果我将writeback_rate_update_seconds 设置为2147483647,那么实际上将什么值传递给schedule_delayed_workschedule_delayed_work 的第二个参数似乎是 long,但这并不意味着操作数在乘法溢出之前被提升为 long,对吗?

【问题讨论】:

  • 不,直到乘法完成后才会提升值,它使用原始参数的类型。
  • 因为它是unsigned,所以溢出会使用模运算来回绕。
  • @Barmar 原谅我的无知,但是“使用模运算环绕”到底是什么意思?这是否意味着乘法就像long 一样完成,但只返回最低有效的 32 位?
  • 我如何找到 HZ 的类型,如果这很重要?
  • 在维基百科中查找模运算。 HZ 大概是个宏,看一下宏定义应该就知道是什么类型了。

标签: c integer-overflow


【解决方案1】:

给定:

#include <stdio.h>
#include <stdlib.h>

int schedule_delayed_work( unsigned long param )
{
    printf("value: %lu\n", param);
    return 0;
}

int main(int argc, char **argv)
{
    unsigned int writeback_rate_update_seconds;
    unsigned int HZ;
    writeback_rate_update_seconds = 2147483647;
    HZ = 1000;
    schedule_delayed_work( writeback_rate_update_seconds * HZ );
    return 0;
}

您将获得4294966296 传递给函数。

如果将函数调用更改为强制转换:

schedule_delayed_work( (unsigned long) writeback_rate_update_seconds * HZ );

...你会得到2147483647000 传递给函数。

我没有查看 C 标准以了解标准行为是什么,但这是通过以下方式测试的:

Apple LLVM version 8.1.0 (clang-802.0.38)
Target: x86_64-apple-darwin16.7.0

【讨论】:

  • 请注意,您看到的行为适用于 unsigned long 为 64 位的系统。对于 MSVC,unsigned long 是 32 位。这是允许的; unsigned long long 是唯一保证 64 位的类型。
  • 谢谢,如果我调整 HZ 以进行签名,我会得到相同的结果(我认为它是一个宏,因此实际上是一个文字 1000,它已签名,但 gets typecast to unsigned 在乘法中)
【解决方案2】:

如果两个操作数都适合unsigned int(如果HZ 是常量1000,则它的类型是int 并且适合unsigned int)它们被提升为unsigned int。使用unsigned 整数,溢出是明确定义的;结果值是计算模的值(UINT_MAX 加一)。即最大结果为UINT_MAXUINT_MAX + 1 将产生 0,UINT_MAX + 2 将产生 1,依此类推。

接收者的类型(这里是接收结果的参数的类型)根本不重要。为避免回绕,请将其中一个参数转换为 更宽的整数类型(例如,unsigned long 在 64 位 Linux 中是 64 位;或者更好的是,使用固定宽度类型,例如 @987654333 @)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-09-27
    • 1970-01-01
    • 2018-07-10
    • 1970-01-01
    • 2014-05-21
    • 2015-08-16
    • 2015-04-11
    • 2011-03-11
    相关资源
    最近更新 更多