代码之家  ›  专栏  ›  技术社区  ›  H.S.

一个变量是否会导致有符号整数溢出(后增量的副作用),然后再也没有在任何表达式中使用它,从而导致UB?

  •  2
  • H.S.  · 技术社区  · 2 年前

    考虑此程序

    #include <limits.h>
    
    int main (void) {
        int i = 0;
    
        // Assume, user is a fair person, following the instruction strictly..
        printf ("Enter a number in the range [0 - INT_MAX] : \n"); 
        scanf ("%d", &i);
    
        while (i++ < INT_MAX) {
            // do some stuff..
            // value of variable i not used in loop body
        }
    
        // value of variable i is not used anywhere after loop body
    
        return 0;
    }
    
    

    在循环条件的最后一次评估中 i++ < INT_MAX ,的值 i 在表达式中将为 INT_MAX 但是 将持有的结果 INT_MAX + 1 (后增量的副作用),本质上是有符号整数溢出。循环条件 (INT_MAX < INT_MAX) 导致 false 并且循环退出。变量的值 在程序中循环体之后的任何地方都不使用,但是,当然,一旦循环退出,它就会保存 INT_MAX+1

    这个程序是否具有未定义的行为?

    PS:

    • 我搜索了一下,发现了几个相关的问题,但它们并不完全相同:

    does-integer-overflow-cause-undefined-behavior-because-of-memory-corruption

    is-it-undefined-behavior-if-the-intermediate-result-of-an-expression-overflows

    在上述两个问题中,都以某种方式使用了导致溢出的变量/表达式的值。

    • 我的问题非常具体,指向了未定义的行为,我不想寻找任何其他方式来做示例程序中显示的事情。我很清楚,如何避免UB。

    • 如果你能在你的帖子中加入引用(如果有的话),支持你的行为(无论是否UB),我将不胜感激。

    3 回复  |  直到 2 年前
        1
  •  3
  •   user229044    2 年前

    这个程序是否具有未定义的行为?

    是的,这很清楚。

    您不必访问的值 i 在它溢出之后,发生溢出,并且一旦发生溢出,就调用了未定义的行为。

    如果有人用GCC编译您的程序并使用 -ftrapv 标志,一旦发生溢出,您的程序就会崩溃,无论您以后是否尝试访问

        2
  •  3
  •   Eric Postpischil    2 年前

    如果你能在你的帖子中加入引用(如果有的话),支持你的行为(无论是否UB),我将不胜感激。

    C 2018 6.5.2.4讨论后缀 ++ .第2段说:

    作为副作用,操作对象的值会递增(即,将适当类型的值1添加到其中)。有关约束、类型和转换以及操作对指针的影响的信息,请参阅加法运算符和复合赋值的讨论

    6.5.6讨论了加法运算符。第5段说:

    二进制的结果 + 运算符是操作数的总和。

    6.5第5段说:

    如果 特殊情况 在表达式求值期间发生(也就是说,如果结果没有在数学上定义,或者不在其类型的可表示值范围内),则行为是未定义的。

    因此,当 i++ 使用进行评估 i 等于 INT_MAX ,它有效地评估 INT_MAX + 1 ,并且出现异常情况,因此程序的行为不是由C标准定义的。

        3
  •  2
  •   dbush    2 年前

    您似乎有一种错误的印象,即未定义的行为意味着您的程序将以您可能意想不到的方式运行。这不是它的意思。

    当一个程序包含未定义的行为时,C标准无法保证该程序会做什么。它可能会崩溃,可能会产生意外结果,或者看起来工作正常。

    正如您从最初的研究中了解到的那样,有符号整数溢出确实是未定义的行为。无论您随后是否尝试使用 i 没关系。您的程序仍然有未定义的行为。

    无论你是 可能的 看看这里面有什么不寻常的行为 特指的 例如,可能不会,但也不能保证这一点。