2

So to be up front, this is related to a homework assignment that I need guidance with. I don't need code or anything, but this is driving me crazy and I need some clarification. I'm not even asking the question in the book.

I have the following code:

int fun(int *c){
*c += 10;
return *c ;
}

void main(){

int a, b;
a = 10;
b = a + fun(&a);
printf("value of a is %d\n", a);
printf("With the function call on the right, ");
printf(" b is: %d\n", b);
a = 10;
b = fun(&a) + a;
printf("With the function call on the left, ");
printf(" b is: %d\n", b);
}

When I run it, I get "value of a is 20" and "with the function call on the right, 40" and "with the function call on the left, 40".

What I am confused about is that I had a very similar question right before

#include<stdio.h>

int fun(int *k) {
*k += 4;
return 3 * (*k) - 1;
}

void main() {
int i = 10, j = 10, sum1, sum2;
sum1 = (i / 2) + fun(&i);
sum2 = fun(&j) + (j / 2);

printf("%d", sum1);
}

And the answer comes out to 46 for sum1 and 48 for sum2 which in my head makes sense with left to right evaluation in codepad.org's compiler. But in Pelles C compiler it comes out to 48. You can see that the code from the first problem is laid out pretty much exactly the same.

I did find this link: Parameter evaluation order before a function calling in C which seems to explain this inconsistency but I want to make sure I'm not way off in my line of thinking. So would it be safe to say that it depends on the compiler and what the compiler feels is most efficient?

Community
  • 1
  • 1
  • Learn about [sequence points](http://en.wikipedia.org/wiki/Sequence_point). There is no sequence point in e.g. the expression `a + fun(&a)`, so the compiler is is free to evaluate either `a` or `fun(&a)` first. – Some programmer dude Nov 25 '14 at 04:12
  • You have undefined behavior – Gopi Nov 25 '14 at 04:13
  • This is basically a duplicate of the question you linked to, the answer to this question is the same. My answer to this question would basically be a rehash of [my answer](http://stackoverflow.com/a/18245704/1708801) to the question you linked. – Shafik Yaghmour Nov 25 '14 at 04:13
  • @Gopi: unspecified, not undefined. – rici Nov 25 '14 at 04:27
  • The other question was similar but it wasn't the same so I wanted to make sure I wasn't missing some fundamental concept when it comes to evaluating this problem with functions and parameters. – nationalgrammarrodeo Nov 25 '14 at 04:31

1 Answers1

2

In both these expressions

sum1 = (i / 2) + fun(&i);
sum2 = fun(&j) + (j / 2);

you have unspecified behavior, because the order of evaluation of the subexpressions of + is unspecified. The compiler is free to evaluate (i/2) and (j/2) before or after the call, as it sees fit.

Unlike && and || operators that force evaluation of their left side before their right side, +, -, *, /, %, and all the bitwise operators allow the compiler to pick the most convenient order of evaluation, depending on its optimization strategy. This means that different compilers may decide to evaluate the sides of + differently.

What this means from the practical perspective is that you should use expressions with side effects no more than once in the same expression. You can rewrite both your expressions to force the order of evaluation that you want, for example

sum1 = i/2;
sum1 += fun(&i);

or

sum2 = sun(&j);
sum2 += j/2;
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • okay, i actually played around with forcing the expressions to be evaluated the exact way you mentioned while I was working on this. it just kind of blows my mind that something like this could be undefined and I thought I was missing some big fundamental concept. – nationalgrammarrodeo Nov 25 '14 at 04:26
  • @nationalgrammarrodeo I think this was a philosophical decision: forcing any specific order of evaluation restricts compiler designers to a specific strategy, potentially interfering with performance. Designers of the standard, on the other hand, tried to avoid anything that would reduce performance, sometimes at the expense of confusing behavior. You found a great illustration of how confusing this could get very quickly with unspecified ordering. – Sergey Kalinichenko Nov 25 '14 at 04:33
  • HI, I have encountered a similar question, but me and another answerer don't agree one the behavior, if it is undefined or unspecified. If you're interested and you have the time, please check this question out: https://stackoverflow.com/questions/37597855/c-order-of-evaluation-of-assignment-statement I would love to hear your opinion. – 2501 Jun 07 '16 at 15:42
  • @2501 I think you are right, side effect inside `fun` makes this undefined, not merely unspecified. Thanks! – Sergey Kalinichenko Jun 07 '16 at 15:55
  • @dasblinkenlight ? I was actually arguing that the result is unspecified and the behavior is defined. http://stackoverflow.com/a/37599439/4082723 The assignment inside the function surrounded by two sequence points. – 2501 Jun 07 '16 at 15:57
  • @2501 I double-checked with the [C11 standard draft](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf), and it looks like there is only one sequence point there - between evaluating of `fun` designator with its actual arguments, and calling the `fun` itself. The assignment of `i` inside `fun` is unsequenced with respect to evaluating `i/2` (section 6.5.5.2.10). There is no sequence point after the call of `fun`, because it is not a library function. – Sergey Kalinichenko Jun 07 '16 at 16:27
  • `;` is also a sequence point. Here is one in the function: `*c += 10;` – 2501 Jun 07 '16 at 16:28
  • @2501 Are you sure that semicolon inside the function counts as a sequence point in the context of the caller? The language in the standard suggests that the assignment inside the function remains unsequenced with respect to evaluation of the argument outside the function: " Every evaluation in the calling function [...] that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function." – Sergey Kalinichenko Jun 07 '16 at 16:40
  • I'm pretty sure. Indeterminately sequenced is not the same as unsequenced. Please read: `5.1.2.3 Program execution, paragraph 3`. The paragraph you quoted is relevant to explain that function executions don't interleave, see the footnote. That text also says: *that is not otherwise specifically sequenced*. In this case it is, via sequence points in the function. A sequence point between A and B guarantees that A is before B. – 2501 Jun 07 '16 at 16:53
  • @2501 I think you are right then, thanks for clarifications! – Sergey Kalinichenko Jun 07 '16 at 17:10