【问题标题】:Where is the second overflow in this piece of code这段代码的第二个溢出在哪里
【发布时间】:2014-07-23 05:21:40
【问题描述】:

这是来自GNU C reference manual Pg 74 的一段代码:

如果您的代码使用有符号循环索引,请确保该索引不能 溢出,以及从索引派生的所有有符号表达式。 这是一个有问题的代码的人为示例,其中有两个实例 溢出。

for( i = INT_MAX - 10 ; i <= INT_MAX; i++)
    if( i+1 < 0 ) //first overflow
    {
        report_overflow();
        break; 
    }

由于这两个溢出,编译器可能会优化掉或 以不兼容的方式转换两个比较 环绕假设。

【问题讨论】:

  • 你能解释一下你的问题吗?
  • 第二个可能是i &lt;= INT_MAX; i++
  • i &lt;= INT_MAX 始终为真,因此循环永远无法退出
  • 我觉得写成只会发生一次溢出。由于break 语句,来自i++ 的第二个不能发生。同意吗?
  • 是的,但编译器可能会将其视为潜在的溢出,这可能会导致优化问题。

标签: c


【解决方案1】:

GNU C reference manual 的意思是你有两个可能的溢出。第一个是i++ 中的声明

for( i = INT_MAX - 10 ; i <= INT_MAX; i++)

第二个是i+1 in

if( i+1 < 0 ) //first overflow

示例 C 代码使用

if( i+1 < 0 ) //first overflow
{
    report_overflow();
    break; 
}

一段代码,而要做到这一点,您依赖于签名的环绕行为。

但是 A.3 附录告诉您不应该依赖签名的环绕行为,因为优化器会利用其未定义的行为并可能生成行为与您预期不同的代码。 if( i+1 &lt; 0 ) 代码就是这种情况,它依赖于当 iINT_MAX 时会发生这种环绕。

总之,上面的代码经过编译器优化后可能会失败。

【讨论】:

  • +1 你正确地说“你不应该依赖环绕行为”,也许重要的是要说明这种情况是因为变量是有符号的,而如果变量是无符号的,则可以保证环绕.
  • @Antonio:在所有已知架构上,都会发生不管变量签名
  • @mvp 这里的重点是优化器,而不是架构,在使用有符号整数时依赖回绕可能会产生strange 行为。在几个线程中更好地描述它,例如123
  • @mvp gnu.org/software/gnu-c-manual/… :“在像 C 这样的语言中,无符号整数溢出可靠地回绕;例如,UINT_MAX + 1 产生零。这是由 C 标准保证的,并且在实践中是可移植的,除非你指定仅适用于特殊应用的激进、非标准优化选项。”
【解决方案2】:

从评论转换:

i &lt;= INT_MAX 始终为真,因此循环永远不会退出。所以这是一个错误,因为 i++ 溢出。

因为它总是正确的,编译器可能会优化这个条件,这显然不是预期的。

【讨论】:

  • 在按原样编写的代码中,我看不到由于i++ 导致的第二次溢出如何影响操作并将其变成无限循环。你能纠正我吗?
  • 您希望增加i 最终会打破循环条件。但是,当 i==INT_MAX 时,再次增加它会使其为负(溢出),因此您的期望永远不会满足,并且循环会永远继续
  • 循环条件被 if 子句打破。不是吗?
【解决方案3】:

由于休息,应该没有
没有休息,这将是一个永恒的循环,并在++i
上溢出 因为i &lt;= INT_MAXi 的所有值都为真(假设i 是一个整数)

【讨论】:

    猜你喜欢
    • 2023-01-14
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多