2

I've been working on embedded C project, and I found code:

x = ++x % 5; 

Now, first of all there are 2 side effect operators on variable x in one expression, assignment and prefix increment operator.

According to C99 standard (ISO/IEC 9899:TC3):

Section 6.5 Expressions

  1. 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 read only to determine the value to be stored.

this should be considered as undefined behavior, but I haven't succeeded to prove that in practice. Tried few compilers on windows (mingw32-gcc, msvc) and on linux:

gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
Ubuntu 18.04 4.15.0-36-generic

So my question is, is this considered undefined behavior in embedded, and is it safe to use this in embedded?

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
mgrumic
  • 39
  • 3
  • What does the assembly say? If you are really worried, compare the assembly generated by this (potentially unsafe) method and a non-side-effect method and see if it's worth worrying about. – Neil Nov 22 '18 at 09:52
  • 6
    Whether it's undefined or not, it's better to just write `x = (x+1) % 5;` – interjay Nov 22 '18 at 09:59
  • 4
    @Neil this would be the prove that this one specific compiler does not exploit the undefined behavior (if it is one), not that it is not undefined behavior. – mch Nov 22 '18 at 10:00
  • 3
    Never write pointless code like this. – Jabberwocky Nov 22 '18 at 10:00
  • 1
    @interjay I know it's better, and I would never write it like `x = ++x % 5`. I would write it as you mentioned. – mgrumic Nov 22 '18 at 10:01
  • 3
    The C99 standard gives ` i = ++i + 1;` as an example of an undefined statement (footnote 73). – interjay Nov 22 '18 at 10:09
  • @Jabberwocky Yeah, it's not my code, I found it and I've been wondering is this considered undefined behavior. – mgrumic Nov 22 '18 at 10:09
  • Embedded systems makes no difference. If anything, various oddball embedded compilers are _more_ prone to go bananas when they encounter UB. – Lundin Nov 22 '18 at 10:35
  • Note: with `int x; ... (x+1) % 5` results are in the range [-4 ... 4]. – chux - Reinstate Monica Nov 22 '18 at 13:05

1 Answers1

3

If I compile the code on gcc, it shows me

source_file.c: In function ‘main’:
 source_file.c:8:7: warning: operation on ‘x’ may be undefined [-Wsequence-point]
      x = ++x % 5; 
        ^

That's the first proof, that this may be UB.

To add to that, the increment (write operation, a.k.a, stored value modification) and assignment (once again, write operation, a.k.a, stored value modification) happens without a sequence point in between, so this is undefined behaviour.

That said, just write

  x = (x + 1) % 5 ;

Much better, readable, and lessens the threat on your life.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • I dare say that the _intention_ of `x = ++x % 5;` is properly carried out. Indeed there is a dead store that may be ignored, or carried out, but the result is the same. Would you agree? – Paul Ogilvie Nov 22 '18 at 10:21
  • @PaulOgilvie I wont bet on it. :) – Sourav Ghosh Nov 22 '18 at 10:23
  • Related: A comment below the other deleted post: _"There's nothing to say that the increment is done before the modulo. A compiler is perfectly free to rewrite that into x = (__temp = (x + 1) % 5, x = x + 1, __temp) and then eliminate the dead store in x = x + 1, converting the whole expression into x = (x + 1) % 5 — in fact, most compilers will do just that when optimizing. The modulo uses the incremented value as operand, but the actual increment of the value need not happen before the modulo. – **aaaaaa123456789** "_ – Sourav Ghosh Nov 22 '18 at 10:24