关于printf中的参数的计算次序的问题。
请看下面的程序:
int main(int argc, char* argv[])
{
int j;
j=10;
printf(" %d %d \n",j=2*3,j*5);
j=10;
printf(" %d %d \n",(j=2*3,j*5),j*8);
j=10;
printf(" %d %d \n",(j=2*3,j*5),j*8,j=100);
return 0;
}
//输出分别为
6 50
30 48
500 800
十分不解,请高手指教,谢谢。
我在cb上运行了一下,你输出结果就有问题呀
如果我没记错的话,输出时是从右往左去看的
你查一下资料看看看
1.逗号运算符:从左到右结合,(a,b);取最后一个值b。
2.而printf语句从右向左计算。
更正一下答案:
(在网友的友情提醒下,发现我之前的回复是错误的。目前已更正,感谢贵阳老马马善福专业维修游泳池堵漏防水工程的贡献!)
1)函数值参求值因为早于参数表压栈,并且值参的计算顺序在C/C++标准中没有明确规定,因此取决于编译器的实现。即不同编译器的计算顺序存二义性,因此应尽量避免使用side effect副作用表达式作为函数参数。【之前的答案,也是错误的答案!】1)C/C++默认函数参数表继承了汇编的栈操作,且值参为运行时动态求值。因此编译器按,运行时动态从函数调用堆栈中依次解析传入的参数,即从右至左顺序执行。
2)逗号表达式是一种运算符,返回值为最后一条子语句的值,并且逗号表达式的结合性为L-R,即从左至右的顺序执行本条语句。
自我诫勉博文
https://blog.csdn.net/hslbloc/article/details/101695188
函数的参数的求值顺序,是未定义行为
,也就是说,不同的编译器编译产生的代码,结果不同。
当你的参数是副作用表达式的时候,则相同的源代码,编译出来的程序,结果不可控,因此这种写法要杜绝
。
作为学校老师,让学生研究这个或者以此出题分析运算结果纯属误人子弟
。
关于未定义行为,参考:
https://blog.csdn.net/pegasuswang_/article/details/12872797
https://blog.csdn.net/baihacker/article/details/9204429
维基百科(需要科学上网)出处:
https://en.wikipedia.org/wiki/Unspecified_behavior
Order of evaluation of subexpressions[edit]
Many programming languages do not specify the order of evaluation of the sub-expressions of a complete expression. This non-determinism can allow optimal implementations for specific platforms e.g. to utilise parallelism. If one or more of the sub-expressions has side effects, then the result of evaluating the full-expression may be different depending on the order of evaluation of the sub-expressions.[1] For example, given
a = f(b) + g(b);
, where f and g both modify b, the result stored in a may be different depending on whether f(b) or g(b) is evaluated first.[1] In the C and C++ languages, this also applies to function arguments. Example:[2]
#include <iostream>
int f() {
std::cout << "In f\n";
return 3;
}
int g() {
std::cout << "In g\n";
return 4;
}
int sum(int i, int j) {
return i + j;
}
int main() {
return sum(f(), g());
}
The resulting program will write its two lines of output in an unspecified order.[2] In other languages, such as Java, the order of evaluation of operands and function arguments is explicitly defined.[7]
简单解释下,在这个程序里,输出In g和In f的顺序是不确定的,可能先输出前者,也可能先输出后者。这是因为作为函数参数,f()和g()的求值顺序不确定
。
不关副作用表达式的事,也不关参数如何入栈(由Calling convention调用约定决定),一个函数的参数入栈当然是固定的,否则调用者和被调用者如何协调一致。
之所以求值顺序不确定,是为了代码的优化,比如
foo(a+b, a+b);
编译器可以优化成
c = a + b;
foo(c,c);
这里还有更复杂的情况,比如
foo(a() + b(), a(), a() + c);
编译器可以有多种优化,比如
_p2 = a();
_p1 = _p2 + b();
_p3 = _p2 + c;
foo(_p1, _p2, _p3);
因为a()在多个参数中公用,所以编译器调整参数求值顺序,先求它。显然,这里的参数的求值顺序规则就非常复杂,所以干脆C规范就对此不做规定,任由编译器“发挥”。
这是为什么参数求值顺序是不确定的根本原因
。
这里涉及"求值顺序"。表达式中子表达式的求值顺序,以及函数参数的求值顺序,C++语言标准没有明确规定。不能假定按从左到右的顺序或某种特定的顺序求值。以怎样的顺序求值,不同的编译器的实现方式可能不同。参考下面的例子:
int f1(int& x) { x += 1; printf("f1, x = %d\r\n", x); return x; }
int f2(int& x) { x *= 2; printf("f2, x = %d\r\n", x); return x; }
int f3(int& x) { x *= x; printf("f3, x = %d\r\n", x); return x; }
int g(int x1, int x2, int x3) { return x1 + x2 + x3; }
int main()
{
int x = 2;
int y1 = g(f1(x), f2(x), f3(x)); // 不能确定编译器以怎样的顺序求值f1(x)、f2(x)和f3(x).
x = 2;
int y2 = f1(x) + f2(x) + f3(x); // 不能确定编译器以怎样的顺序求值f1(x)、f2(x)和f3(x).
printf("%d, %d\r\n", y1, y2); // y1和y2可能结果不同.
}
不同于函数参数列表,内建(非用户定义)的逗号运算符按从左到右的顺序求值,并返回最右边的表达式的值。参考下面的代码:
x = 2;
int y3 = (x += 1, x *= 2, x *= x); // y3 =36, x = 36
x = 2;
int y4 = (f1(x), f2(x), f3(x)); // y4 = 36, x = 36
有关求值顺序的详细内容,请参考:https://zh.cppreference.com/w/cpp/language/eval_order