C and C++ coding style for best performance

In many cases, the performance cost of a C construct is not obvious, and sometimes is even counter-intuitive.

Some of these situations are as follows:

  • Whenever possible, use int instead of char or short.

    In most cases, char and short data items take more instructions to manipulate. The extra instructions cost time, and, except in large arrays, any space that is saved by using the smaller data types is more than offset by the increased size of the executable program.

  • If you have to use a char, make it unsigned, if possible.

    A signed char takes another two instructions more than an unsigned char each time the variable is loaded into a register.

  • Use local (automatic) variables rather than global variables whenever possible.

    Global variables require more instructions to access than local variables. Also, in the absence of information to the contrary, the compiler assumes that any global variable may have been changed by a subroutine call. This change has an adverse effect on optimization because the value of any global variable used after a subroutine call will have to be reloaded.

  • When it is necessary to access a global variable (that is not shared with other threads), copy the value into a local variable and use the copy.

    Unless the global variable is accessed only once, it is more efficient to use the local copy.

  • Use binary codes rather than strings to record and test for situations. Strings consume both data and instruction space. For example, the sequence:
    #define situation_1 1
    #define situation_2 2
    #define situation_3 3
    int situation_val;
    situation_val = situation_2;
    . . .
    if (situation_val == situation_1)
    . . .

    is much more efficient than the following sequence:

    char situation_val[20];
    . . .
    if ((strcmp(situation_val,"situation_1"))==0)
    . . .
  • When strings are necessary, use fixed-length strings rather than null-terminated variable-length strings wherever possible.

    The mem*() family of routines, such as memcpy(), is faster than the corresponding str*() routines, such as strcpy(), because the str*() routines must check each byte for null and the mem*() routines do not.