为了消除代码的副作用,如何纠正对运算符优先级的错误假设?

Geo*_*etu 1 c c++ debugging coding-style compiler-warnings

在查看某人的代码时,我遇到了类似于下面的情况,其中错误(基本上是一些糟糕的编程习惯)不是直接可见的.根据所使用的编译器,i/i++可能是01.

int foo(int n) {
    printf("Foo is %d\n", n);
    return (0);
}

int bar(int n) {
    printf("Bar is %d\n", n);
    return (0);
}

int main(int argc, char *argv[]) {

    int x = 0;
    int(*(my_array[3]))();
    int i = 1;
    int y = i/++i;

    printf("\ni/++i = %d, ", y);

    my_array[1] = foo;
    my_array[2] = bar;
    (my_array[++x])(++x);
}
Run Code Online (Sandbox Code Playgroud)

因此,输出是Foo is 2或者Bar is 2.

我的问题可能被认为过于宽泛,但我想知道:

  1. 为什么会发生这种情况/为什么编译器允许这样做?(我检查了几个编译器,根本没有警告)
  2. 我们怎样才能纠正这种奇怪的行为?(例如,我正在为之工作的项目是巨大的;如果编译器也允许更糟糕的事情,如堆利用/bss溢出不一致的同步,会发生什么?在实现这一点之后,一个人不会在晚上睡得好.)
  3. 我意识到市场上有很多编码风格的书籍,但另一位程序员将如何决定哪一项产出最好呢?(假设没有预期的输出 - Foo is 2并且Bar is 2对使用代码的程序员没有任何意义)

M.M*_*M.M 5

i/++i导致未定义的行为,就像my_array[++x](++x).

它不是运营商优先级或评估顺序问题; 这是一个排序问题.(编码器可能认为存在与优先级相对应的副作用的顺序,而事实上并非如此).有关更详细的说明,请参阅此主题.

除非您确实知道自己在做什么,否则可以通过不使用递增或赋值运算符作为子表达式来避免这种错误.在这些情况下:

int y = i / (i+1);
++i;
Run Code Online (Sandbox Code Playgroud)

my_array[x+1](x+1);
x += 2;
Run Code Online (Sandbox Code Playgroud)

或任何意图.

编译器没有义务检测到这些,尽管有些编译器仍然会这样做.最新版本的gcc应该警告i/++i.如果您认为这还不够好,那么请考虑加入gcc开发团队:)

有静态代码分析工具可以更好地检测未定义的行为.


归档时间:

查看次数:

110 次

最近记录:

10 年,12 月 前