Not logged in, Join Here! or Log In Below:  
 
News Articles Search    
 

 Home / General Programming / Sequence points Account Manager
 
Archive Notice: This thread is old and no longer active. It is here for reference purposes. This thread was created on an older version of the flipcode forums, before the site closed in 2005. Please keep that in mind as you view this thread, as many of the topics and opinions may be outdated.
 
Thamas

March 31, 2005, 03:35 PM

Hi,

Are there any C++ language lawyers in the audience? ;)
Does anyone know whether the following code has undefined behaviour or not?

  1.  
  2. int i, n;
  3. i = 1;
  4. n = ++i * ++i;

(Don't worry, I don't seriously want to write that code; this is for a paper on C++ technicalities I'm writing for class.) I know about `sequence points' and why ``a = ++i'' has undefined behaviour. All compilers I tried give n == 9, which seems reasonable. Most people I asked thought it should be 6, but conceded that is probably not what the standard says. I found this paragraph in the ANSI C standard: ``Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored.'' I don't fully understand what is being said here, but the way I read it, it says n should be 4. (Also, this is from the C standard, not C++.) If anyone knows, I'd rather prevent having to delve into the standard myself since I'm under a tight schedule ;). Thanks in advance. Regards, Thomas van Dijk

 
Chris

March 31, 2005, 04:23 PM

It's a clear violation of the standard, and you found the respective sentence already.

1. Clearly there is no sequence point within the expression in question.
You can find in the standard what language constructs make sequence points. Expressions don't.

2. The variable i gets modified *twice*, in violation of what is required.

3. When doing the second ++i, the compiler needs to know i's value. The sentence you quoted says that, in order to determine i's values, the compiler shall not execute the first ++i again, but look at the first ++i's result. In the former case, i would senselessly even be 4, in the latter it's only 3.

4. The compiler is free to evaluate both the left and the right operand of the * operator in any order it likes, and assume i changes at most once.

So the compiler goes
initialize : i = 1
left operand : ++i --> i = 2
right operand: ++i --> i = 3
operator * : * --> 3 * 3 --> 9.

the last being an optimization it may do due to this constraint.
It is more efficient code if you can assume that either the left or the right
operand do not actually change i's values, because then you need to store one temporary value less.

Look at it in pseudo assembly of a stack machine language:

  1.  
  2. load from i
  3. add  1
  4. store to i
  5. store to temp1
  6.  
  7. add 1
  8. store to i
  9. store to temp2
  10.  
  11. load from temp1
  12. multiply both loaded values
  13. store to result
  14.  


Better:
-------

  1.  
  2. // standard allows us to assume i doesn't change here
  3. load from i
  4. add  1
  5. store to i   // but it does
  6.  
  7. // but that it changes once only here
  8. add 1      
  9. store to i    
  10.  
  11. load from i
  12. multiply both loaded values
  13. store to result
  14.  


So yes, the intention probably was
"increment i and multiply the result with i incremented again",
but the compiler evaluates the operands first, and multiplies afterwards.

Another rule important in this context is that order of evaluation is not guaranteed. So if the multiplication were not commutative, the result would be even more unpredictable. Consider

++i % ++i.

Does that mean 2 % 3, or 3 % 2 ? It will evaluate to 3 % 3 for the same reason.

 
Thamas

March 31, 2005, 04:39 PM

Thanks a lot, Chris. This was exactly what I'd hoped to hear, but I wasn't really sure.

p.s.: the actual context was bashing macros.

  1. #define SQUARE(x) (x)*(x)
  2. int i, n;
  3. i = 1;
  4. n = SQUARE( ++i );


This gets expanded into the code in my first post. I wrote that not only doesn't do what you would think it would, but also that it had undefined behaviour. But then I started doubting...

 
This thread contains 3 messages.
 
 
Hosting by Solid Eight Studios, maker of PhotoTangler Collage Maker.