1

I only know i = i++; is undefined behavior, but if there are two or more functions called in an expression, and all the functions are the same. Is it undefined? For example:

int func(int a)
{
    std::cout << a << std::endl;
    return 0;
}

int main()
{
    std::cout << func(0) + func(1) << std::endl;
    return 0;
}
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
miskcoo
  • 185
  • 1
  • 6

3 Answers3

12

The behavior of the expression func(0) + func(1) is defined in that the result will be the sum of the results obtained by calling func with a parameter of 0 and funcwith a parameter of 1.

However, the order in which the functions are called is probably implementation dependent, although it might be unspecified. That is, the compiler could generate code equivalent to:

int a = func(0);
int b = func(1);
int result = a + b;

Or it could generate:

int a = func(1);
int b = func(0);
int result = a + b;

This normally won't be a problem unless func has side effects that depend on the order of calls.

Community
  • 1
  • 1
Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
  • 1
    Or `func(0)` and `func(1)` could execute in parallel, and assuming a thread-safe `cout`, the output could be `10\n\n1\n`. – Ken Y-N Sep 20 '13 at 01:13
  • @KenY-N: True enough. – Jim Mischel Sep 20 '13 at 01:14
  • Does this mean that if I change a global variable `i` in `func`, the result of `i` is undefined ? – miskcoo Sep 20 '13 at 02:15
  • If `func` contained the statement `i = a;` where `i` was a global, then the value of `i` after the statement in `main` would be implementation dependent. It could be `0` or it could be `1`, depending on which function call was executed last. – Jim Mischel Sep 20 '13 at 02:21
  • 1
    @KenY-N, no the calls can not occur in parallel. If calling func() set a global variable, this would introduce a data-race, which would inject undefined behavior into the program. Since many function calls access or modify global state (especially if they're written for a single thread of execution), this would break all kinds of programs. – Adam H. Peterson Sep 20 '13 at 02:44
  • 1
    @user2482012 Note that all side effects of statements are completed before the next statement is executed. So modifying `i` within `func` won't cause undefined behavior. – Shafik Yaghmour Sep 20 '13 at 03:07
  • The compiler could also generate `if (PhaseOfMoon() > 0.5) { ... func(0) first ...} else { ... func(1) first ...}`. The astronomical calculations would be unlikely of course, but a compiler which was e.g. unrolling a loop might discover that the first iteration could benefit from evaluating its operands in a different sequence from later ones, so repeated execution *of the same piece of code* may not yield consistent sequence. – supercat Dec 11 '13 at 19:34
3
std::cout << func(0) + func(1) << std::endl;

Whether the function call func(0) or func(1) executes first, is implementation dependent. After that, there is a sequence point, and func(0) + func(1) is output.

But by definition, it's not called undefined behavior.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
3

The behavior of this program is not undefined but it is unspecified, if we look at the draft C++ standard section 1.9 Program execution paragraph 15 says(emphasis mine):

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [ Note: 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. —end note ] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

and if we check section 5.7 Additive operators which covers + and - that section does not specify an ordering so it is unsequenced.

In this case func has a side effect since it is outputting to stdout and so the order of the output is going to depend on the implementation and it even could change for subsequent evaluations.

Note that the ; ends an expression statement and section 6.2 Expression statement says:

[...]All side effects from an expression statement are completed before the next statement is executed.[...]

so although the order of the function calls is unspecified, the side effects of each statement are completed before the next.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • Another key is later in 1.9p15, where it says: "Every evaluation in the calling function (including other function calls) [...] is indeterminately sequenced with respect to the execution of the called function." As p13 defines, that means "A is sequenced before B or B is sequenced before A, but it is unspecified which." This is important, because while the part from 6.2 you quoted (and also 1.9p14) says that the single `cout`s in the two functions cannot mingle, it would not prevent multiple `cout`s in the two functions to interleave. – Sebastian Redl Sep 20 '13 at 13:45