【问题标题】:C is integer math equivalent with unsigned math?C是整数数学等价于无符号数学?
【发布时间】:2020-12-30 10:46:38
【问题描述】:

那么我可以将值转换为无符号值,执行操作并转换回来,并得到相同的结果吗?我想这样做是因为无符号整数会溢出,而有符号则不能。

【问题讨论】:

  • 总之,有时。
  • 如果结果溢出,则不会进行任何转换。如果计算的中间部分可能溢出,则转换为更大的类型,然后返回,例如 intlong longunsignedunsigned long long
  • 我不想防止溢出,我希望溢出不会崩溃

标签: c math unsigned


【解决方案1】:

无符号整数算术在 C 术语中不会溢出,因为它被定义为模 2N,其中 N em> 是按照 C 2018 6.2.5 9 进行操作的无符号类型的位数:

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

对于其他类型,如果发生溢出,则行为未由 C 标准定义,按照 6.5 5:

如果在计算表达式期间出现异常情况(即,如果结果未在数学上定义或不在其类型的可表示值范围内),则行为未定义。请注意,不仅结果是未定义的;程序的整个行为是未定义的。它可能会给出你不期望的结果,它可能会陷入陷阱,或者它可能会执行与你期望的完全不同的代码。

关于你的问题:

那么我可以将这些值转换为无符号值,执行操作并转换回来,并得到相同的结果吗?

我们有两个问题。首先,考虑a + b 给定int a, b;。如果a + b 溢出,则行为未由 C 标准定义。所以我们不能说转换为unsigned、添加和转换回int是否会产生相同的结果,因为a + b开始时没有定义结果。

其次,根据 C 6.3.1.3,转换回部分是实现定义的。考虑int c = (unsigned) a + (unsigned) b;,它将unsigned 和隐式转换为int 以存储在c 中。第 1 段告诉我们,如果 sum 的值可以用 int 表示,则它是转换的结果。但是第 3 段告诉我们如果值在 int 中不可表示会发生什么:

否则,新类型是有符号的,值不能在其中表示;结果要么是实现定义的,要么引发实现定义的信号。

GCC,例如,defines the result to be the result of wrapping modulo 2N。因此,对于 int c = (unsigned) a + (unsigned) b;,GCC 将产生与 int c = a + b; 相同的结果,如果 a + b 包裹模 2N。但是,GCC 不保证后者。优化时,GCC 预计不会发生溢出,这可能导致它消除程序允许发生溢出的任何代码分支。 (GCC 可能有一些关于溢出处理的选项。)

此外,即使有符号算术和无符号算术都进行了换行,使用无符号值执行操作并将其转换回在数学上不会产生与使用有符号值执行操作相同的结果。例如,考虑-3/2int 结果为 -1。但是如果-3转换为32位无符号,则结果值为232-3,那么(int) ((unsigned) -3 / (unsigned) 2)为2-31-2 = 2,147,483,646。

【讨论】:

    猜你喜欢
    • 2015-01-31
    • 1970-01-01
    • 1970-01-01
    • 2021-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多