This function seems to pack 4 characters into a 32-bit integer, check for an error condition, and then return the int. While acc starts with an undefined value, one could argue that the undefined value is shifted out 8 bits at a time until the whole word is defined.
If this explanation makes sense to you, you might think that the function should always work. But according to the language specifications, the function is still undefined. One can think of the specification as a contract between the programmer and the compiler. If the programmer follows the rules of the specification, the compiler should produce the expected code. But any undefined behavior in the program effectively voids this contract, so that the compiler may do some unexpected things.
This example may seem academic, but it is not. It turns out that the most straightforward implementation of a modern constant propagation algorithm will “optimize” the code so that error() is never called.
This rule appears in MISRA C++ as well, although it is in a different form. MISRA C++ Rule 8-5-1 states: “All variables shall have a defined value before they are used.” The description of the rule goes on to discuss dubious embedded environments that do not initialize static variables to zero before further requiring: “Each class constructor shall initialize all non-static members of its class.”
. The right hand operand of a logical && or || operator shall not contain side effects
. (C Rule 12.4/C++ Rule 5-14-1/Required)
A side-effect is defined as an expression that accesses a volatile object, modifies any object, writes to a file, or calls off to a function that does any of these things, possibly through its own function calls.
The nomenclature “side-effect” may sound ominous and undesirable, but after some reflection, it becomes clear that a program cannot do much of anything useful without side-effects.
As an example of where this rule is helpful is as follows:
This may work fine in a lot of cases. But, even if it is safe, it can easily become a hazard later. For example, a programmer might think that process_packet() is always called. Therefore, he or she reasons, it should be safe to close a file or free some memory in process_packet().
A safer way to write this would be:
depending on the true intent of the code.
This rule is not a portability or safety issue, per se, because the behavior of the || and && operators are well defined. But, the rule is intended to eliminate a common source of programming errors.