Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this operation properly sequenced?

Tags:

c++

c

In the following code excerpt from a larger piece of code presented

void func(int* usedNum, int wher) {
    *usedNum = *usedNum + 1 > wher ? ++(*usedNum) : wher + 1; 
}

int main(void) {
   int a = 11, b = 2; 
   func(&a, b); 
}

a warning is emitted

 warning: operation on '* usedNum' may be undefined [-Wsequence-point]
 *usedNum = *usedNum + 1 > wher ? ++(*usedNum) : wher + 1; 

Is there a problem with the code?

My source of doubt was this and the part where it says

The sequence points in the logical expressions such as && and || and ternary operator ?: and the comma operator mean that the left hand side operand is evaluated before the right hand side operand. These few operands are the only operands in C++ that introduce sequence points.

tl;dr

For those that find torturing to read through the comments: The initial question was not properly posed and it would be unfair to create misconceptions. My view on the topic had two sides

  1. The ternary operator does not mess up (in an unexpected way) the sequence points (which holds, the two branches are sequenced in every version of C,C++ - see the link provided)

  2. Is x = ++x the problem? As seen in the coliru link, we compile for c++14. There the operation is well defined (references on the comments), but older versions of c++ and c view this as undefined. So why is there a warning?

Answers focus both in C and C++; this is a good link. Lastly the C tag was there initially (my bad) and can't be removed because existing upvoted answers refer to it

like image 227
Nikos Athanasiou Avatar asked Feb 10 '15 09:02

Nikos Athanasiou


People also ask

What is sequencing operation?

Operation Sequencing. It is to plan the order of the operation by process, regarding the fixed orders through the Operation Order Release Planning. It is to grasp the progress status of the operation, to consider the priority, setup time, and etc., and to make an operation sequencing list.

Why is sequence of operation is important?

The purpose of the sequence of operation is to define how the system will function, throughout its various operating modes. If the sequence of operation is not defined and implemented correctly, then system performance will suffer. The project begins with the development of the Owner's Project Requirements (OPR).

What is sequencing in production and operations management?

Sequencing means grouping production operations into production batches and arranging them by priority. Metal industry casting operations are a great real-life example of this. Typically, casting starts from the purest products and moves on toward progressively more alloyed products.


2 Answers

When the condition is true, it is the equivalent of saying x = ++x. In C, and versions of C++ prior to C++11, this constitutes a modification and a read of x without an intervening sequence point and therefore is undefined behaviour if the truthy branch is followed. From C++11 onwards, x = ++x is sequenced and well defined.


Edit To clarify some issues from comments.

1) this would be well defined in all C and C++ standards:

x = (++x, x); // RHS evaluates to x after increment

because the expression in the parentheses involves the comma operator, which introduce a sequence point between the evaluation of its operands. So the whole expression on the RHS evaluates to x after an increment. But the code in your question does not involve the comma operator.

2) The ternary operator introduces a sequence point

It is a sequence point between the condition and the two branches. But this doesn't introduce a sequence point between either branch and the assignment.

like image 177
juanchopanza Avatar answered Oct 17 '22 08:10

juanchopanza


The warning you are getting is probably due to the fact that you are compiling your code in c++03 mode or older. In C99 and C++03, expression

x = ++x;

invokes undefined behavior. The reason is that between two sequence points an object can't modify more than once.

This rule is changed in C11 and C++11. According to C11, the rule is as follows:

C11:6.5 Expressions:

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

When *usedNum + 1 > wher will be true, then

*usedNum = *usedNum + 1 > wher ? ++(*usedNum) : wher + 1;   

would be equivalent to

*usedNum = ++(*usedNum);  

and according to new rule this is well defined in C++11 this is because the side effect by pre ++ is sequenced before the side effect by = operator. Read this answer for more detailed explanation.

But the same expression *usedNum = ++(*usedNum); invokes undefined behavior in C11. The reason is that there is no guarantee that side effect by = operator is sequenced after the side effect of pre ++ operator.


Note: In the expression

a = x++ ? x++ : 0; 

there is sequence point after the first x++ and hence behavior is well defined. Same is true for

x = (++x, x);  

because there is a sequence point between the evaluation of left and right operand and hence side effect is sequenced.

like image 30
haccks Avatar answered Oct 17 '22 07:10

haccks