Surprises in C code - Embedded.com

Surprises in C code

The C language is quite flexible and expressive; these are some of the reasons why it has been successful and resilient to being replaced by “better” languages. An example of its flexibility is the possibility to write an expression in a number of ways that are functionally equivalent. This enables the style of coding to be adapted to personal needs. However, there is a catch: sometimes, apparently equivalent code has subtle differences. This can occur in the simplest code and we will explore some possibilities in this article.

It is common for C to provide several different ways to do something, all of which are exactly equivalent. For example, given that x is a normal int variable, each of the following statements will do exactly the same job:

x = x + 1;
x += 1;
x++;
++x;

In each case 1 will be added to x. The only possible difference is that a less capable compiler might generate slightly better code for the last two options (which would be a hint that getting a better compiler would be worthwhile).

The two forms of the ++ operator, used in this way, produce the same result. However, if the value of the expression is used, the pre-increment and post-increment are different, thus:

y = x++;   // y has the value of x before the increment
y = ++x;   // y has the value of x after the increment

Interestingly the post-increment is slightly more “expensive”, as storage needs to be allocated to keep the old value of x. However, a compiler would probably optimize this away. If the storage is allocated when the expression value is not used, then a new compiler is definitely required!

If, instead of being an int, x were a pointer to int, the adding 1 would have the effect of adding 4 (on a 32-bit machine). If this comes as a big surprise, a brush up on pointer arithmetic is in order.

However, sometimes constructs that appear to be equivalent have very subtle differences…

Probably the simplest thing that you can do in any programming language is assign a value to a variable. So, in C, we might write:

alpha = 99;
beta = 99;
gamma = 99;

Of course, this might be written more compactly like this:

alpha = beta = gamma = 99;

And these are 100% equivalent. Or are they?

Most of the time, these two constructs are entirely equivalent, but there are (at least) four situations when choosing one or the other might make a difference:

Firstly, and most prosaically, each variable is separate and perhaps a comment indicating why it is set to this value might be appropriate.

Second, it is always good to write maintainable code. Maybe, at some point in the future, the code might need to be changed so that all three variables are not set to the same value. The first format lends itself more readily to modification.

The third reason relates to substandard compilers, which might generate code like this for the first construct:

mov r0, #99
mov alpha, r0
mov r0, #99
mov beta, r0
mov r0, #99
mov gamma, r0

The second construct gives the hint that r0 only needs to be loaded once. Again, a better compiler would not need the hint.

Lastly, there is the question of execution order. In the first construct, it is entirely clear that alpha will be assigned first and gamma last. A compiler will interpret the second construct thus:

alpha = (beta = (gamma = 99));

This means that the assignment order is reversed. But does that matter? Most of the time, it does not. But if these were device registers, not ordinary variables, it might make a big difference. It is very common for hardware to need set-up values to be loaded in a precise sequence.

So, I would say that the multiple assignments in one statement construct should be avoided.

Overall, although C is a small language, it could be argued that it could be even smaller by giving less ways to do things. The result might be clearer, more maintainable code.


Colin Walls has over forty years’ experience in the electronics industry, largely dedicated to embedded software. A frequent presenter at conferences and seminars and author of numerous technical articles and two books on embedded software, Colin is an embedded software technologist with Mentor, a Siemens business, and is based in the UK. His regular blog is located at: https://blogs.sw.siemens.com/embedded-software/. He may be reached by email at colin_walls@mentor.com.

Related Contents:

For more Embedded, subscribe to Embedded’s weekly email newsletter.

5 thoughts on “Surprises in C code

  1. Damn good article. Given that an embedded C programmer is working closer to the bone, these things are possibly more obvious to you. They should be made known to the readers and you’ve done a nice job of that. Good work, keep on trucking…

    Log in to Reply
  2. Another major source of surprises is the interrupts.

    for example, in the case of chain assignment:
    alpha = beta = gamma = 99;
    it is possible that an interrupt reassigns beta to 77, right after it was assigned 99. Then the result will be:
    gamma = 99;
    beta = gamma;
    beta = 77;
    alpha = 77

    However, in the case of separate assignments:
    alpha = 99;
    beta = 99;
    gamma = 99;
    only beta gets reassigned by the interrupt to 77.

    One would expect some atomicity in this compound statement, but that is not defined in C. The programmer can disable interrupts during the execution of the compound if he wishes so.

    Log in to Reply
  3. I would say these surprises are just “oversmart” code.
    How many times does one in real world one needs to write “alpha = beta = gamma = 99;”?
    In other words how much is the benefit of such code’s optimized output compared to to the risk involved?

    Also, such assignments make commenting difficult, so the readability is poor.
    I would question the competence of the architect and designer when a programmer is writing such code.

    In the good old bad days, when memory was scanty and clocks in KHz, readability had to be sometimes sacrificed for parsing efficiency.
    In the modern world, where excellent optimizing compilers are available, memory is plentiful, processor speeds are in 100s of MHz should, we must call such code simply as unsafe or wrong.

    Log in to Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.