I do, however insist on making everything explicit. I'm not a huge fan of implicit anything... Maybe that's something I need to get over?
No, that is very good practice and a good habit. Particularly, there are many dangerous, implicit type promotions going on in C, that explicit type casts can prevent.
However, if you want to be explicit, you must actually have quite a deep understanding of what's going on between the C lines. Until you do, you will end up causing more problems than you solve with this coding practice. Also, you do a couple of pointless things that only clutter down the code.
Here are my comments on your code:
- Do not define your own bool type. Instead use the standard
bool
type in stdint.h.
(int) 0
This cast is pointless and adds nothing of value. Integer literals are always of the type int
. Enumeration constants are also always of the type int
.
register
is an obsolete keyword from the dark ages, when compilers were worthless at optimizing code. Today, a modern compiler does a much better job at optimizing the code than you do, so let it do its job. Also, the register
keyword causes various side-effects: for example you can't take the address of a register variable. So never use register
, because there is never a reason to do so. That keyword just remains in the language for backwards compatibility.
- Similarly, it is often best to let the compiler handle inlining in most cases. Because while inlining makes the code faster, it also makes the executable much larger. The compiler is likely better than you at determining when to optimize for size and when to optimize for speed.
- Always use
{}
after each statement, even if there is only one line of code following it. Skipping {}
is dangerous practice that almost certainly leads to bugs sooner or later.
You want to be explicit but miss a few cases where it actually matters.
1 << offset
means that you do left shift on a signed integer. Assuming 32 bit integers, the case of 1 << 31
leads to undefined behavior. Generally, in 99.9% of the cases it doesn't make any sense whatsoever to use bitwise operators on signed integers. If you wish to write safe code, be explicit and type 1u << offset
.
Because of the above, *x |= (1 << offset);
implicitly stores an int
into an unsigned int
, which is potentially dangerous in some cases.
And also because of the above, you apply ~
to a signed int, which is always dangerous practice.
You have no function declarations, only definitions. You also don't declare the local functions as static
, which is proper practice for functions that are private to the specific module.
As others have commented, naming a bool "value" and using it to store values is confusing. uint8_t
would have been a more suitable type to use in this case.
In general, it is always better to use the types from stdint.h when you do bit manipulations.
bool
datatype.#include <stdbool.h>
\$\endgroup\$