4

Say you have x = exp1 + exp2 in c. It might be evaluated by first evaluating exp1 then exp2 and adding the results however it may evaluate exp2 first.

How do you find out which side is evaluated first? I would like to make x = 1/2 depending on which one was evaluated first.

Any ideas?

Ketameme
  • 101
  • 6
  • 6
    This sounds like a bit of an [XY problem](http://xyproblem.info/) - I'm trying to think of a reason why one would want to do this :/ – Oliver Charlesworth Mar 30 '17 at 13:13
  • 9
    You don't. You can't control the compiler like that. You write your code so it doesn't matter. – Jonathan Leffler Mar 30 '17 at 13:14
  • 1
    You might find [this reference about evaluation ordering](http://en.cppreference.com/w/c/language/eval_order) useful. – Some programmer dude Mar 30 '17 at 13:14
  • 6
    You can easily find it out by calling functions with side effects for exp1 and exp2 (i.e. printing something out)... However, you cannot rely on that it will always be the same order in any case – Ctx Mar 30 '17 at 13:16
  • Just sprinkle some undefined behavior on it `int y = 0; int x = y + ++y;` – StoryTeller - Unslander Monica Mar 30 '17 at 13:16
  • Part of some homework I gotta do, I have to make a program to purposely give different results haha. – Ketameme Mar 30 '17 at 13:17
  • 6
    @Ketameme I seriously doubt that you fully understood the task – Ctx Mar 30 '17 at 13:18
  • 4
    ... but if you did, @Ketameme, then send your instructor over here for a bit of slapping around^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H vigorous chastisement. – John Bollinger Mar 30 '17 at 13:20
  • I think you mean this: `10 / 20 * 1000` which is not the same as `10 * 1000 / 20` because in the first case you will get `10 / 20 = 0 * 1000 = 0` and in the second case you get `10 * 1000 = 10000 / 20 = 500`. – Jabberwocky Mar 30 '17 at 13:24
  • @MichaelWalz Im trying to do somethin like this: i = ++i + i++; // undefined behavior, i = i++ + 1; // undefined behavior, f(++i, ++i); // undefined behavior, f(i = -1, i = -1); // undefined behavior, http://en.cppreference.com/w/c/language/eval_order – Ketameme Mar 30 '17 at 13:27
  • 2
    Even if you do that, and compile, then the compiler will determine which expression to evaluate first at compile time, meaning, if you run the program 100 times, you will always get the same result. Plus, the compiler's decision of which expression to evaluate first will not be random either, so if you compile and then run it 100 times, you will also get the same result -- you'll not be demonstrating the undefined behavior... (you'd need to compile with different compilers, which act differently to demonstrate this...) – blackghost Mar 30 '17 at 13:36
  • If your intent is to purposely produce different outputs each time, use [rand()](http://en.cppreference.com/w/c/numeric/random/rand). – Haem Mar 30 '17 at 13:39
  • @John I understand now, thanks john :) – Ketameme Mar 30 '17 at 13:43
  • 1
    @John You make invalid assumptions here, on some platform the c-compiler might for example parallelize the evaluation of the parameters, then the order might vary from execution to execution. – Ctx Mar 30 '17 at 13:46
  • @Ctx -- Interesting... The compiler wouldn't start a new thread, so in the end you have set of processor instructions which are run in a specific order. Having said that, it _is_ possible that there is a complex instruction which can be run in parallel with another instruction, and there is a hardware race condition caused by this. I also suppose the compiler wouldn't protect against those race conditions in an expression, so I could see a potential for differing answers there.,, – blackghost Mar 30 '17 at 14:28
  • @Ketameme The `i = i++;` mess is not undefined behavior because of the order of evaluation, but because of unsequenced side-effects together with value computations of the same variable. – Lundin Mar 30 '17 at 14:52

2 Answers2

5

Okay, you can do it like this:

#include <stdbool.h>
#include <stdio.h>

static int first(int value)
{
  static bool first = false;
  if (!first)
  {
    first = true;
    return value;
  }
  return 0;
}

int main(void)
{
  const int x = first(1) + first(2);
  printf("got %d\n", x);
}

On ideone.com, I got 1.

Note that this proves nothing, since there is no defined behavior here. The C99 draft says (in 6.5 Expressions, paragraph 3):

The grouping of operators and operands is indicated by the syntax.72) Except as specified later (for the function-call (), &&, ||, ?:, and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • When would an answer like 2 occur, is it just dependent on how compiler handles it? – Ketameme Mar 30 '17 at 13:41
  • 2
    @Ketameme Note [this comment](http://stackoverflow.com/questions/43118951/order-of-operands-in-c#comment73318703_43118951). A subsequent run of the code may result in a different answer - so not a compiler issue in that case. Unwind: nice simple answer to the question, even if OP's higher level goal in unclear. – chux - Reinstate Monica Mar 30 '17 at 13:48
0

How do you find out which side is evaluated first?

Generally this is not specified by the standard. C11 6.5/3:

Except as specified later, side effects and value computations of subexpressions are unsequenced. 86)

...

86) In an expression that is evaluated more than once during the execution of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be performed consistently in different evaluations.

"Specified later" refers to a few special cases where the order of evaluation is specified, namely for the following operators: || && ?: ,, which are all guaranteed to be evaluated left-to-right.

As we can see from the cited note, we can't even know if the same program will treat the same expression consistently. This is called unspecified behavior, which means that compiler will behave in one of several well-defined ways but we can never know or assume which way. You should always write your programs so that the order of evaluation does not matter.


If you wish to fool around with code that prints which order the compiler decided to evaluate a particular expression (this time), you could do:

#include <stdio.h>

int func(void)
{
  static int x=0;
  return x++;
}

int main (void)
{
  printf("%d", func() << func());
}

This will either give 0<<1 == 0 (left-to-right) or 1<<0 == 1 (right-to-left). But such code has no practical purpose.

Lundin
  • 195,001
  • 40
  • 254
  • 396