在 C 函数调用中,参数传递/计算的顺序是什么?
我正在运行这个 C 程序:
#include<stdio.h>
void print(int* a, int* b, int* c, int* d, int* e)
{
printf("%d %d %d %d %d\n", *a, *b, *c, *d, *e);
}
int main()
{
static int a[] = {97, 98, 99, 100, 101, 102};
int* ptr = a + 1;
print(++ptr, ptr--, ptr, ptr++, ++ptr);
ptr = a+ 1;
printf("%d %d %d %d %d\n", *++ptr, *ptr--, *ptr, *ptr++, *++ptr);
int i = 0;
printf("%d %d %d", i++, ++i, ++i);
}
一个编译器将其打印为输出:
99 99 98 98 100
99 99 98 98 100
0 2 3
另一个编译器将其打印为:
100 100 100 99 100
100 100 100 99 99
2 3 3
现在,我很困惑发生了什么。正确的顺序是什么?
I am running this C program:
#include<stdio.h>
void print(int* a, int* b, int* c, int* d, int* e)
{
printf("%d %d %d %d %d\n", *a, *b, *c, *d, *e);
}
int main()
{
static int a[] = {97, 98, 99, 100, 101, 102};
int* ptr = a + 1;
print(++ptr, ptr--, ptr, ptr++, ++ptr);
ptr = a+ 1;
printf("%d %d %d %d %d\n", *++ptr, *ptr--, *ptr, *ptr++, *++ptr);
int i = 0;
printf("%d %d %d", i++, ++i, ++i);
}
One compiler prints this as the output:
99 99 98 98 100
99 99 98 98 100
0 2 3
Another compiler prints this:
100 100 100 99 100
100 100 100 99 99
2 3 3
Now, I am confused what is happening. What is the correct order?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
函数调用的求值在 2018 版 C 标准条款 6.5.2.2 中指定,但该条款没有指定参数的求值顺序。任何订单都是允许的。
因此,
print(++ptr, ptr--, ptr, ptr++, ++ptr);
的行为不是由 C 标准定义的。 6.5 2 说:ptr
是一个标量对象。 (C 2018 6.2.5 21 说“算术类型和指针类型统称为标量类型。”)++ptr
和ptr--
更改ptr 的副作用。 (
++ptr
的“主要”作用是计算ptr
的增量值。它的副作用是更新ptr
存储的值code>.) 由于没有对这些副作用强加顺序,因此满足 6.5 2 的条件,因此它适用,并且 C 标准未定义该行为。请注意,这并不仅仅意味着
ptr
可以按照编译器选择的任何顺序进行更新。当 C 标准说行为未定义时,这意味着它根本没有对行为强加任何要求。对对象的两次更新可能会发生冲突,以不同的顺序更新对象的不同字节,产生一个无法通过以任何顺序的单独连续更新获得的值。 (例如,当编译器在原始机器中使用两字节更新实现四字节指针时,可能会发生这种情况。)或者编译器中的优化器可以识别代码没有定义的行为并将其从程序中完全删除,或者将其替换为其他代码。 (例如,如果程序包含两个代码序列之间的分支,并且优化器认识到一个分支在特定情况下将具有未定义的行为,则它可以省略评估选择的代码并仅使用另一分支上的代码。 )Evaluation of function calls is specified in the 2018 version of the C standard clause 6.5.2.2, but this clause does not specify the order of evaluation of the arguments. Any order is permitted.
As a consequence of this, the behavior of
print(++ptr, ptr--, ptr, ptr++, ++ptr);
is not defined by the C standard. 6.5 2 says:ptr
is a scalar object. (C 2018 6.2.5 21 says “Arithmetic types and pointer types are collectively called scalar types.”)++ptr
andptr--
changeptr
by a side effect. (The “main” effect of++ptr
is to evaluate to the incremented value ofptr
. Its side effect is to update the stored value ofptr
.) Since there is no ordering imposed on these side effects, the conditions of 6.5 2 are satisfied, so it applies, and the behavior is not defined by the C standard.Note that this does not just mean that
ptr
may be updated in whatever order the compiler happens to choose. When the C standard says behavior is undefined, that means it does not impose any requirements on the behavior at all. Two updates to the object might conflict, updating different bytes of it in different orders, producing a value that is impossible to obtain by separate consecutive updates in any order. (This could happen, for example, when a compiler implements four-byte pointers using two-byte updates in a primitive machine.) Or the optimizer in the compiler could recognize the code does not have defined behavior and remove it completely from the program or replace it by other code. (For example, if the program contains a branch between two sequences of code, and the optimizer recognizes one branch would have undefined behavior in a particular circumstances, it can omit the code that evaluates the choice and use only the code on the other branch.)