What to use instead of magic numbers in C

I am currently using static const in my code instead of using the "magic numbers" mentioned in the "static const" vs "# define" vs "enumeration" .

void checkInvalidResponse (uint8_t response) { static const uint8_t INVALID_RESP = 0xFF; if (response == INVALID_RESP) { /* Code for invalid response */ } } 

However, I believe that using static const will consume memory in compiled code for INVALID_RESP. The operator will also translate to machine code, which makes a LOAD from memory, followed by a comparison, instead of comparing with the value provided as part of the instruction. It's right? If so, then this solution will not be optimal in terms of speed and memory?

I am currently modifying the code to use #defines

 void checkInvalidResponse (uint8_t response) { #define INVALID_RESP 0xFF if (response == INVALID_RESP) { /* Code for invalid response */ } } 

However, since #define has no scope, will the behavior of the cut-and-paste attribute in #define be consistent across multiple compilers? For example, if INVALID_RESP is redefined later, will any code in the lines after the redefinition use the new value?

Another approach I reviewed is using enums.

 void checkInvalidResponse (uint8_t response) { typedef enum { INVALID_RESP = 0xFF } resp_t; if ((resp_t)response == INVALID_RESP) { /* Code for invalid response */ } } 

However, casting to an enumeration will allocate more memory than necessary (the processor will compare 32 bits (?) Instead of 8-bit comparison).

What is the best method to use instead of using magic numbers in code?

+6
source share
4 answers

I think that in all cases, the compiler, at least with -O2 enabled, will generate the same code. It was pretty hard to fool compilers to do stupid things.

As a rule, magic numbers are defined in the general header and are used as necessary throughout the code.

The bigger the question for you, is it important? Is it something that is on the critical path of your code, and something that you are going to do a very high percentage of the time? Given the name, I would not have thought.

Moving the definition to the header file will make your code less distracting. In checkInvalidResponse reader did not care if INVALID_RESPONSE presented, only that the test passes or fails.

+3
source

In the C language, const objects are not constants at the language level, which greatly limits the usability of const to define manifest constants. Please note that this is not about the efficiency of the generated code, but about the basic reliability ("compilation") of the code: in the C language const entities are simply not allowed in contexts that require constants.

For this reason, in C, the only truly universal and universal approach to defining manifest constants is the C preprocessor (i.e. #define ), and enum is another alternative to vialble, but only where applicable (a significant drawback of the enum constant in C is that they unconditionally signed int ).

Just use #define and don't try to "expand" constants. Everything is in order there. But if for some reason you need to limit the scope of #define 'd to a constant, you can always use #undef for this purpose.

+1
source

enum guaranteed by the standard to support unsigned int widths.

If you use #define , the implicit width specification is because the pre-compiler will simply replace the character with a number (or whatever else was defined), so you can add L to the end of your number and guarantee long values.

Honestly, I never used more integers for transfers ...

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

6.7.2.2 Listing Qualifiers
[...]
Image Constraints An expression specifying the value of an enumeration constant must be an integer constant expression that has a value that is represented as int.
[...]
Each type enumerated must be compatible with char, an integer type with a signed or unsigned integer type. The choice of type is determined by the implementation, but should be able to display the values โ€‹โ€‹of all members of the enumeration.

0
source

All this will be specific to the compiler and platform. And if you really do not need to throw out a few bytes for installation in ROM, this does not really matter. Using a compiler is almost always less error prone than a preprocessor, so stick with constants.

Also keep in mind that the compiler is always allowed to embed, if that makes sense.

0
source

All Articles