views:

180

answers:

6

Here is my function:

void abc(char  *def, unsigned int w, unsigned int x, unsigned int y, unsigned int z)
{
   printf("val 1 : %d\n", w);
   printf("val 2 : %d\n", x);
   printf("val 3 : %d\n", y);
   printf("val 4 : %d\n", z);
}

and here is where I call this function:

unsigned int exp[4] = { 1, 2, 3, 4 };
unsigned short count = 0;
abc(anyarray, exp[count++], exp[count++], exp[count++], exp[count++]);

and here is the output that I expect:

val1 : 1
val2 : 2
val3 : 3
val4 : 4

but what I get is completely reverse of it:

val1 : 4
val2 : 3
val3 : 2
val4 : 1

I don't know why? Any help would be appreciated.

A: 

This is because of the calling convention. In _cdecl, the default calling convention for c/c++ programs (according to microsoft), the parameters are passed on the stack to the function in reverse order. Because of this, the parameters are also evaluated in reverse order.

Alexander Rafferty
That is not entirely true. There's nothing in the standard that says arguments are passed to the stack right to left (eg: the way gcc does it). In fact, nothing says there has to be a stack at all.
NullUserException
I am writing my program on 64 bit arch. so i assume here that fucntion parameters will be stored in registers.
Jewel Thief
Yes, but I am talking about the calling convention that this particular compiler uses, which seems to be the most common.
Alexander Rafferty
You cannot count on that.
Alexander Rafferty
Even without considering the increment and decrement operators, an important take-away from this is that you can't rely on the order of evaluation of function parameters
Andrew
I really don't understand the DV, I simply explained the reason for his problem, and a possible workaround.
Alexander Rafferty
Hey, I'll give you +1 for explaining why the values are exactly reversed (I was puzzled by that). But the proposed solution is not good because it does rely on the vagaries of the compiler.
Andrew
Relying on a particular compiler implementation is just nonsense. Have you never needed to port code?
Gabriel Schreiber
No, not yet, but I do understand your point. I deleted the example.
Alexander Rafferty
+2  A: 

You've invoked undefined behavior, by modifying count more than once without an intervening sequence point.

Jim Lewis
+5  A: 

You should not use the ++ operator, operating on the same variable, more than once in the same statement. The order in which the operation will be performed is not defined.

Try:

abc(anyarray, exp[count], exp[count+1], exp[count+2], exp[count+3]);  
count += 4; 
Andrew
`You should not use the ++ operator more than once in the same statement` Why can't we? `c = a++ + b++` is well defined.
Prasoon Saurav
@Prasoon: OK, edited to address this point. But fancy multiple uses of increment operators leads to the sort of problem in the original question. I would write c = a + b; a++; b++; myself
Andrew
+1  A: 

You are counting on the parameters being evaluated left to right. You can't make any assumptions about the order that they're evaluated. In this case, it looks like the compiler is evaluating them right-to-left.

Also, you may want to look up sequence points, because it may be that you shouldn't use the ++ operator in this way.

jwismar
There's no "may" about it. The standard names this very thing as being **undefined behavior**, meaning the compiler is free to do anything - even to cause nasal demons.
greyfade
Yeah, but ironically it also means that it may work entirely the way you expect it to. You're right of course - the "may" is me avoiding being too prescriptive in a response, although, in this case, a little prescriptiveness is probably appropriate.
jwismar
+6  A: 

abc(anyarray, exp[count++], exp[count++], exp[count++], exp[count++]);

The order of evaluation of arguments of abc is unspecified but the expression invokes undefined behaviour because you are trying to modify a variable count more than once between two sequence points.

Furthermore using incorrect format specifier in printf() also invokes UB. Please make sure you have used correct format specifiers(i.e %u for unsigned int) in printf().

Prasoon Saurav
:) [ ](http://a)
NullUserException
It would be possible to get all values 1, or all values 4 too.
Jonathan Leffler
I think it is important to note that 'count' is a scalar variable and hence it is UB. This is not an issue if 'count' if of UDT
Chubsdad
+6  A: 

From standard docs, 5.4

Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified58) Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.

An example from the Standard docs itself,

i = v[i ++]; / / the behavior is undefined

And it is for the very same reason that

abc(anyarray, exp[count++], exp[count++], exp[count++], exp[count++]); is undefined..

liaK