Tenderfoot: Introduction to Magic (Numbers that is...)
Once upon a time, while participating in a source code review, I stumbled across the following C code in a header file:
struct Foo { //various structure fields char string_buffer[45+3]; //buffer requires about 45 bytes };
My right eyebrow raised, I took a note, and continued with the code review, only to later stumble into this line of code in the body of a C function:
char * temp_string_buffer = (char*) malloc(45+3);
Again, I took a note on this function, and continued with the code review.
So, why did I pause and take note of this particular code? We will skip over the eye catching “requires about” statement in the related code comment and focus on this primary issue, what experienced software engineers will immediately recognize as:
“magic numbers”
For those transitioning into embedded software engineering from electrical engineering, or for those just getting started in their embedded software engineering career, this post is for you.
What is a magic number? A magic number is any constant value that is repeated more than once in the source code without a single reference defining the constant. In other words, it is a constant value that is used repeatedly and is therefore violating the DRY principle. In most cases I would broaden that definition to include nearly all constants used in the software, even if the value is only used in a single location in the code. In the example code snippet, we find two magic numbers, the “45” and the “3.” Embedded software is exposed to many forms of magic numbers, some of which traditional desktop or server software is rarely required to handle. Examples might include:
- Device register addresses
- Microcontroller specific memory maps
- Device data sheet values
- Default values specific to the product, such as calibration constants, algorithm constants, or message type constants
- User interface string constants
- Magic numbers discovered the hard way: work around values for device faults, timing values, or other special values discovered by the engineer during development and troubleshooting
- Government or industry specification defined values
Given that our software is certainly going to require the use of various constants, what exactly is wrong with the use magic numbers in our code? The primary issue is code maintenance followed quickly by software readability.
The maintenance issue involves the risk of overlooking the copied magic numbers when the values are inevitably modified. This is an easy mistake to make during maintenance, as we all suffer from human frailties, distractions, and forgetfulness. Everything we can do when writing software to help prevent future errors is to our benefit and the benefit of a future engineer called upon to modify the software. Remember: “Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live”. The maintainer might just buy you a beer if he finds clean code with single points of code to modify!
Readability is improved because we are now using a single named constant variable, #define, or constexpr to describe the “magic number” in terms that are readable and provide additional meta-information on the value itself. For example, in our C code example snippet, we might change the code to:
#define MY_STRING_MAX_PLUS_NULL (45+1) //Per XYZ spec dated Dec 2011, page 10, Section 3.3. +1 for null struct Foo { //various structure fields char string_buffer[MY_STRING_MAX_PLUS_NULL]; };
With the other code snippet modified to:
char * temp_string_buffer = (char*) malloc(MY_STRING_MAX_PLUS_NULL);
With these changes we now have code that is easier to read and trivial to maintain. If the specification changes we now have a single #define to modify and all dependent code will be compiled with the new value. Don’t forget to comment with useful, not repetitious, information on the value, and the resulting code will be easier to understand for your future self and/or any other software maintainers that inherit the software.
So, what form of magic numbers have you conjured lately?
Matthew Eshleman
- Comments
- Write a Comment Select to add a comment
magic number is any constant value that is repeated more than once
I'd leave off the "that is repeated more than once". If I saw
x = 45 + 3;
in some code without any obvious meaning, I'd flag as a magic number.
I would also look at the buffer usage to make sure the buffer does not overflow.
I would also look at the usage to make sure the buffer does not overflow
To post reply to a comment, click on the 'reply' button attached to each comment. To post a new comment (not a reply to a comment) check out the 'Write a Comment' tab at the top of the comments.
Please login (on the right) if you already have an account on this platform.
Otherwise, please use this form to register (free) an join one of the largest online community for Electrical/Embedded/DSP/FPGA/ML engineers: