Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IO-performing functions called in same statement: Undefined or unspecified?

Tags:

c++

I am starting to learn C++ from C++ Primer (5th edition). Working through the chapter on expressions, I came up with an example program that has me wondering:

int f1()
{
    cout << "f1\n";
    return 1;
}

int f2()
{
    cout << "f2\n";
    return 2;
}

int main() {
    int i = f1() + f2();
    return 0;
}

I am unsure whether this program invokes undefined or merely unspecified behavior. I know that the order in which functions f1 and f2 are called is unspecified. Each function writes to standard output as a side effect, so at best, the order in which the lines are printed is unspecified. At worst, this invokes undefined behavior.

I know the answer lies somewhere in the C++ standard, but it is quite technical for my current level of understanding. A gentler explanation would be much appreciated.

like image 874
ADR Avatar asked Jan 31 '16 23:01

ADR


People also ask

Is unspecified behavior undefined behavior?

Undefined Behavior results in unpredicted behavior of the entire program. But in unspecified behavior, the program makes choice at a particular junction and continue as usual like originally function executes.

What is undefined behavior in programming?

So, in C/C++ programming, undefined behavior means when the program fails to compile, or it may execute incorrectly, either crashes or generates incorrect results, or when it may fortuitously do exactly what the programmer intended.

Why does C++ have undefined behavior?

Undefined behavior exists mainly to give the compiler freedom to optimize. One thing it allows the compiler to do, for example, is to operate under the assumption that certain things can't happen (without having to first prove that they can't happen, which would often be very difficult or impossible).

What does <= mean in C++?

Checks if the value of left operand is less than or equal to the value of right operand, if yes then condition becomes true. (A <= B) is true.


2 Answers

Unspecified Behavior

The behavior of the program varies between implementations and the conforming implementation is not required to document the effects of each behavior. For example, order of evaluation, whether identical string literals are distinct, the amount of array allocation overhead, etc. Each unspecified behavior results in one of a set of valid results.

Order of Evaluation

[T]here is no concept of left-to-right or right-to-left evaluation in C++. This is not to be confused with left-to-right and right-to-left associativity of operators: the expression f1() + f2() + f3() is parsed as (f1() + f2()) + f3() due to left-to-right associativity of operator+, but the function call to f3 may be evaluated first, last, or between f1() or f2() at run time.

If order is important, you do

int a = f1();
int b = f2();
int i = a + b;

If order isn't important, then the code is perfectly fine.

like image 131
Yam Marcovic Avatar answered Oct 15 '22 00:10

Yam Marcovic


The topic of "undefined behavior" is quite the nuisance on the site. For quite a while, there were many questions asking "Is this undefined behavior?" and answerers rushing to say "yes" when it actually wasn't the case. I believe what you're thinking of are cases like this:

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, and they are not potentially concurrent (1.10), the behavior is undefined.

[ Example:

void f(int, int);
void g(int i, int* v) {
  i = v[i++];        // the behavior is undefined
  i = 7, i++, i++;   // i becomes 9

  i = i++ + 1;       // the behavior is undefined
  i = i + 1;         // the value of i is incremented

  f(i = -1, i = -1); // the behavior is undefined
}

end example ]

Both modifying an object and calling a library I/O function are side effects. Other than that, there is no relation whatsoever that implies your example has undefined behavior.

The other problem I have are answerers who would rather dump a bunch of nice-sounding standardese that is more difficult to parse than the human-friendly version. As a result, people tend to miss the bigger picture. Here is an example:

§1.9/15 For each function invocation F , for every evaluation A that occurs within F and every evaluation B that does not occur within F but is evaluated on the same thread and as part of the same signal handler (if any), either A is sequenced before B or B is sequenced before A.

Translation: If A and B would not otherwise be sequenced, then they are indeterminately sequenced. By definition, indeterminately sequenced means they can occur in any order but may not overlap.

Furthermore, in inexact terms, the operands of the + operator are unsequenced. So + does not represent a "sequence point". Therefore, f1() and f2() are indeterminately sequenced and you can infer that it's unspecified behavior.

TL;DR: Forget the standard, focus on learning the language. You get too bogged down into details and you lose sight of the bigger picture and confuse things. Here's a human-friendly treatise on the subject

like image 21
user5883629 Avatar answered Oct 15 '22 02:10

user5883629