Reputation: 23
I've been going through an old source project, trying to make it compile and run (it's an old game that's been uploaded to GitHub). I think a lot of the code was written with C-style/C-syntax in mind (a lot of typedef struct {...} and the likes) and I've been noticing that they define certain macros with the following style:
#define MyMacroOne (1<<0) //This equals 1
#define MyMacroTwo (1<<1) //This equals 2, etc.
So my question now is this - is there any reason why macros would be defined this way? Because, for example, 0x01 and 0x02 are the numerical result of the above. Or is it that the system will not read MyMacroOne = 0x01 but rather as a "shift object" with the value (1<<0)?
EDIT: Thanks for all of your inputs!
Upvotes: 2
Views: 3865
Reputation: 1323793
To illustrate how this (1<<0)
syntax is more practical, consider this example from the code-base of Git 2.25 (Q1 2020), which moves the definition of a set of bitmask constants from 0ctal literal to (1U<<count)
notation.
See commit 8679577 (17 Oct 2019) by Hariom Verma (harry-hov
).
(Merged by Junio C Hamano -- gitster
-- in commit 8f40d89, 10 Nov 2019)
builtin/blame.c
: constants into bit shift formatSigned-off-by: Hariom Verma
We are looking at bitfield constants, and elsewhere in the Git source code, such cases are handled via bit shift operators rather than octal numbers, which also makes it easier to spot holes in the range.
If, say,
1<<5
was missing:
- it is easier to spot it between
1<<4
and1<<6
- than it is to spot a missing
040
between a020
and a0100
.
So instead of:
#define OUTPUT_ANNOTATE_COMPAT 001
#define OUTPUT_LONG_OBJECT_NAME 002
#define OUTPUT_RAW_TIMESTAMP 004
#define OUTPUT_PORCELAIN 010
You get:
#define OUTPUT_ANNOTATE_COMPAT (1U<<0)
#define OUTPUT_LONG_OBJECT_NAME (1U<<1)
#define OUTPUT_RAW_TIMESTAMP (1U<<2)
#define OUTPUT_PORCELAIN (1U<<3)
Upvotes: 0
Reputation: 60058
You can always use constant integer expression shifts as a way to express (multiples of) powers of two, i.e. Multiple*(2 to the N-th power) = Mutliple << N
(with some caveats related to when you hit the guaranteed size limits of the integer types and UB sets in*) and pretty much rely on the compiler folding them.
An integer expression made of integer constants is defined as an integer constant expression. These can be used to specify array sizes, case labels and stuff like that and so every compiler has to be able to fold them into a single intermediate and it'd be stupid not to utilize this ability even where it isn't strictly required.
*E.g.: you can do 1U<<15
, but at 16 you should switch to at least 1L<<16
because ints
/unsigneds
are only required to have at least 16 bits and leftshifting an integer by its width or into the place where its sign bit is is undefined (6.5.7p4):
The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 x 2E2 , reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 x 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
Upvotes: 0
Reputation: 16043
It makes it more intuitive and less error prone to define bit values, especially on multibit bitfields. For example, compare
#define POWER_ON (1u << 0)
#define LIGHT_ON (1u << 1)
#define MOTOR_ON (1u << 2)
#define SPEED_STOP (0u << 3)
#define SPEED_SLOW (1u << 3)
#define SPEED_FAST (2u << 3)
#define SPEED_FULL (3u << 3)
#define LOCK_ON (1u << 5)
and
#define POWER_ON 0x01
#define LIGHT_ON 0x02
#define MOTOR_ON 0x04
#define SPEED_STOP 0x00
#define SPEED_SLOW 0x08
#define SPEED_FAST 0x10
#define SPEED_FULL 0x18
#define LOCK_ON 0x20
Upvotes: 2
Reputation: 67476
It is convenient for the humans
for example
#define PIN0 (1u<<0)
#define PIN5 (1u<<5)
#define PIN0MASK (~(1u<<0))
#define PIN5MASK (~(1u<<5))
and it is easy too see if there is a correct bit position. it does not make the code slower as it is calculated at the compile time
Upvotes: 1
Reputation: 1701
Macro are just replacement text. Everywhere macro is replaced by replacement text!! This is convenient especially if you want to name something constant which otherwise is prone to mistakes.
Upvotes: 0