开发者

How are arguments evaluated in a function call? [duplicate]

This question already has answers here: Why are these constructs using pre and post-increment undefined behavior? (14 answers) Closed 4 years ago.

Consider this code:

void 开发者_Go百科res(int a,int n)
{
    printf("%d %d, ",a,n); 
}

void main(void) 
{
    int i; 
    for(i=0;i<5;i++)
        res(i++,i);
    //prints 0 1, 2 3, 4 5

    for(i=0;i<5;i++)
        res(i,i++);
    //prints 1 0, 3 2, 5 4
}

Looking at the output, it seems that the arguments are not evaluated from right to left every time. What exactly is happening here?


The order of evaluation of arguments in a function call is unspecified. The compiler can evaluate them in whichever order it might decide on.

From the C99 standard 6.5.2.2/10 "Function calls/semantics":

The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.

If you need to ensure a particular ordering, using temporaries is the usual workaround:

int i; 
for(i=0;i<5;i++) {
    int tmp = i;
    int tmp2 = i++;

    res(tmp2,tmp);
}

Even more important (since it results in undefined behavior, not just unspecified behavior) is that you generally can't use an operand to the increment/decrement operators more than once in an expression. That's because:

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored. (6.5/2 "Expressions")


As per the standard: The order of argument evaluation is unspecified. Further, note that there are no sequence points (sort of mile-posts) when arguments are evaluated. Hence, modifying the same variable as part of the argument, more than once evokes undefined behavior. This is a FAQ 3.2. The code you have posted thus has ambiguous behavior.

It may be of surprise as to why the standard leaves this as unspecified: The simple reason being that this allows the compiler to perform some optimizations. (See discussion related to Q2 of GOTW #56.)

In most implementations though, this is determined by what is known as the calling convention. The calling convention not only determines the order, but also imposes the responsibility of cleaning up the stack either on the caller or the callee.

Also note, main always returns an int.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜