The first statement sets bit 8 of the variable line_a. The second statement sets bit 7 of line_b. You might think that the third statement sets bit 6 of line_c. It doesn’t. It sets bits 2, 4, and 5. The reason is that in C any numeric constant that begins with 0 is interpreted as an octal constant. Octal 64 is the same as decimal 52, or 0x34.
Unlike hexadecimal constants that begin with 0x, octal constants look like decimal numbers. Also, since octal only has 8 digits, it never has extra digits that would give it away as non-decimal, the way that hexadecimal has a, b, c, d, e, and f.
Once upon a time, octal constants were useful for machines with odd-word sizes. These days, they create more problems than they’re worth. MISRA C prevents programmer error by forcing people to write constants in either decimal or hexadecimal.
. Typedefs that indicate size and signedness should be used in place of the basic types.
(C Rule 6.3/C++ Rule 3-9-2/Advisory)
This is a portability requirement. Code that works correctly with one compiler or target might do something completely different on another. For example:
On a target where an int is a 16-bit quantity, j*1024 will overflow and become a negative number when j >= 32. MISRA C suggests defining a type in a header file that is always 32-bits. For example one could define a header file called misra.h that does this. It could define an 32 bit type as follows:
Then the original code could be written as:
Strict adherence to this rule will not eliminate all portability problems based on the sizes of various types1
, but it will eliminate most of them. Other MISRA rules (notably 10.1 and 10.3) are meant to fill in these gaps.
The potential drawback to such a rule is that programmers understand the concept of an “int”, but badly-named types may disguise what the type represents.
Consider a “generic_pointer” type. Is this a void * or some integral type that is large enough to hold the value of a pointer without losing data? Problems like this can be avoided by sticking to a common naming convention. Although there will be a slight learning curve for these names, it will pay off over time.
Another problem is that using a type like UI_16 may be less efficient than using an “int” on a 32-bit machine. While it would be unsafe to use an int in place of a UI_16 if the code depends on the value of the variable being truncated after each assignment, in many cases the code does not depend on this. In some cases, an optimizing compiler can remove the extra truncations; in the rest, the extra cycles can be considered the price of safety.
----------------------------1. The “integral promotion” rule states that before chars and shorts are operated on, they are cast up to an integer if an integer can represent all the values of the original type. Otherwise, they are cast up to an unsigned integer. The following code will behave differently on a target with a 16-bit integer (where it will return 0) than it will on a target with a 32-bit integer (where it will return 65536).