【问题标题】:Newbie here: Different results on PC and MAC. Why? [duplicate]新手在这里:PC 和 MAC 上的不同结果。为什么? [复制]
【发布时间】:2015-02-03 23:06:27
【问题描述】:

我现在正在努力学习 C/C++ 的基础知识。我正在学习 Lynda.com 上的课程

我的问题涉及第 4 章“C/C++ 基础培训课程中的宏观注意事项”中的一系列代码。我已按照所有设置程序在 Mac 上正确设置 Xcode 和 Eclipse,在 PC 上正确设置 Eclipse。当我在 MAC 和 PC 上运行此代码时,我会得到不同的结果。只是想了解为什么会发生这种情况,以及我可以做些什么来获得相同的结果。

代码如下:

// working.c by Bill Weinman <http://bw.org/>

#include <stdio.h>
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )

int increment() {
    static int i = 42;
    i += 5;
    printf("increment returns %d\n", i);
    return i;
}

int main( int argc, char ** argv ) {
    int x = 50;
    printf("max of %d and %d is %d\n", x, increment(), MAX(x, increment()));
    printf("max of %d and %d is %d\n", x, increment(), MAX(x, increment()));
    return 0;
}

在 PC 上我得到这个结果:

increment returns 47
increment returns 52
max of 50 and 52 is 50
increment returns 57
increment returns 62
increment returns 67
max of 50 and 67 is 62

在 MAC(Xcode 和 Eclipse)上我得到这个结果:

increment returns 47
increment returns 52
increment returns 57
max of 50 and 47 is 57
increment returns 62
increment returns 67
increment returns 72
max of 50 and 62 is 72

为什么会发生这种情况,我该怎么做才能确保结果相同?

【问题讨论】:

  • 顺便说一句:IDE 没有任何意义,确切的编译器和您给它的选项几乎在每种情况下都会确定顺序。虽然理论上它可能会随着程序的每次执行而改变。
  • @AdrianoRepetti 几乎可以肯定是一个 dup,但因为我对这个问题有一个答案,所以我不想用锤子关闭它。

标签: c++ c eclipse xcode


【解决方案1】:

这里有未指定的结果。

printf() 中的评估顺序未定义。 一旦您在同一个 printf 中有多个 increment() 调用,那么您将永远不知道哪个最先执行以及如何评估它们。

【讨论】:

    【解决方案2】:

    未定义完整表达式中所有元素的求值顺序。所需要的只是每个子表达式在计算之前对其操作数进行完全计算。在函数调用的情况下,参数可以按任何顺序进行计算,事实上,一个参数可能只是在另一个参数被完全计算时才被部分计算。

    首先,让我们扩展宏:

    printf("max of %d and %d is %d\n", x,
                                       increment(),
                                       ((x) > (increment()) ? (x) : (increment()));
    

    (糟糕,这里还有一个问题:如果increment() 大于x,那么它会再次被调用。将MAX 宏设为函数,这样参数只计算一次!)

    以下所有序列都是可能的。我在这里省略了x 的评估,因为它不会改变。

    • 计算第二个参数increment(),然后是x &gt; increment(),最后是选择的?: 操作数。 (这可能是您所期望的顺序。)
    • 计算x &gt; increment(),然后是选择的?: 操作数,最后是第二个参数increment()
    • 计算 x &gt; increment(),然后是第二个参数 increment(),最后是选择的 ?: 操作数。

    这些都可能产生不同的结果,它们都是对您的代码的正确解释。

    当您在单个完整表达式中调用多个函数时,您应该确保这些函数没有任何副作用,或者每个函数的副作用不会改变任何其他函数的行为职能。否则,在不同的编译器(或同一编译器的不同版本!)上编译可能会改变结果。

    作为一个额外的例子,即使是看起来很简单的表达式increment() &gt; increment()也有一个未指定的结果,因为操作数的计算顺序没有定义;如果先计算左操作数,则结果为假,否则为真。

    在更复杂的示例((a + b) * (c + d)) 中,编译器可以按照它喜欢的任何顺序评估abcd。所需要的只是ab 必须在a + b 可以被评估之前,cd 必须在c + d 可以被评估之前,并且a + bc + d 必须是在最终运算符 * 之前进行评估。

    【讨论】:

      【解决方案3】:

      这里有两个问题。

      您依赖于编译器选择的任何东西来评估 printf() 的参数。首先评估的语句会修改后面语句的值。将 increment() 调用移出参数列表。将 increment() 的结果存储在变量中,并将这些变量传递给 printf()。

      另外,MAX 的宏扩展可能导致任一参数被计算一次或两次。所以即使在相同的操作系统和编译器上,你也会得到尴尬的结果。要解决此问题,请按照我建议的方法来存储 increment() 结果。将这些变量传递给 MAX()。

      【讨论】:

        猜你喜欢
        • 2021-09-19
        • 1970-01-01
        • 2012-12-12
        • 2016-03-31
        • 1970-01-01
        • 1970-01-01
        • 2022-11-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多