Shortcutting Conditionals

There are times when you need cycle-precise timing. Every loop has to be the same length down to the instruction. There is one thing that C does that can mess with your timing, shortcutting conditionals.

For efficiency, C will stop evaluating conditionals when their value is apparent. Conditionals are evaluated from left to right, but C stops evaluating as soon as the result is guaranteed, this is known as shortcutting or short circuiting. For instance, a complex conditional that uses an AND is guaranteed to be false when the first term is false. No evaluation of the second term is required.

if ((false) and (true)) {     // This will always be false

When an OR is used and the first term is true, it doesn’t matter what the value of the second term is, the condition is true.

if ((true) or (false)) {      // This will always be true

Two situations result from this. First, the timing of the program is not predictable since it is dependant on the values of the terms, causing a timing asymmetry, since the later terms might not get executed. Secondly, anything that you put in the second term may not be executed.

if ((apples == oranges) and (EOF != getchar(ch))) {

The getchar will not get executed because the first term is never true. If your program relies on the second term getting executed, you have a bug.

The more complex of the two problems is the time asymmetry. You will encounter this problem when you are doing time-critical processing, like bit-banging on an exceedingly small and inexpensive processor, short of cycles and short of peripherals.

What can you do if this is a problem? This is not something that can be turned off with an optimizer flag, it is a part of the language (this was news to me, thank you for cluing me in Elecia) but I can think of two ways:

1) Use a bunch of boolean variables, explicitly assign each term to one of the variables, then use the variables in the condition:

#include <iso646.h>

bool functionAReturn;
bool functionBReturn;

functionAReturn = AFunction( params);
functionBReturn = SomeOtherFunction( someOtherParams);

if (functionAReturn or functionBReturn) {

Both of the terms are executed, but shortcutting will still happen in the evaluation of the two booleans, so the asymmetry in the timing will be small but still present.

2) To minimize the asymmetry in timing, you could add some simple bit manipulation.

bool result;

result = functionAReturn bitor functionBReturn;

if (result == true) {

Unless I screwed up, this should give constant timing.

Chris Svec pointed out to me that shortcutting is used when dealing with pointers. You never want to use a pointer that is invalid, so we first check the pointer for validity, then use the pointer. If the pointer is invalid, the pointer dereference never happens:

if ((ptr != NULL) and (ptr->member)) {

When using complex conditionals, remember that shortcutting will be applied and it cannot be turned off. Don’t put anything in the second term of a conditional that must be executed for correct functioning of your program. If execution is necessary, break out the terms and execute them explicitly.

This post is part of a series. Please see the other posts here.

Corner 1 of the 2016 Formula 1 Grand Prix du Canada in Montreal. Nico Rosberg takes the a shortcut down the escape road after running out of room.

Corner 1 of the 2016 Formula 1 Grand Prix du Canada in Montreal. Nico Rosberg takes the a shortcut down the escape road after running out of room.