I stumbled on the following stuff in someone's source code in C:
typedef struct {
u32 reg;
} reg_t;
#define _REG(r) ((const reg_t){.reg=(r)})
#define REG_A _REG(123)
#define REG_B _REG(456)
...
and it makes me wonder: what might be the purpose of such sorcery? Couldn't just a simple numerical constant be defined instead? Why do they define a structure, with just one member, and then use C99's compound literals to initialize it? Is there some obscure benefit that I'm missing here that requires such syntax?
(At first I was puzzled by that syntax as well, until I found out that it's a C99 extension. I knew about the "designated initializers", but I didn't know that they can be used this way, with something that looks like a type cast, but from what I understood, it's just C99's way of doing something akin to C++'s constructors. Still, I don't know why do they use this trick here in particular, and what would happen if they didn't.)
what might be the purpose of such sorcery?
The purpose is to make _REG
have type const reg_t
.
Couldn't just a simple numerical constant be defined instead?
Anything is possible. Most probably, you could rewrite the code.
Why do they define a structure, with just one member, and then use C99's compound literals to initialize it?
To make the type of _REG
be const reg_t
. For type checking.
it's a C99 extension
An "extension" in C language, is an extra part, outside the standard. Specific compilers have specific "extensions", which "extend" the basic language. Like GCC compiler has __attribute__()
function attributes syntax, which other compilers do not.
Compound literals are not extra. They are internal, inside C99 standard. All C99 compilers have compound literals.
Simple type checking example:
uint8_t reg_get(const reg_t ret);
int main() {
reg_get(REG_A); // OK
reg_get(123); // error
}
Note: with the code shown, there is no reason for them to be #define
. I would do static const reg_t REG_A = {123};
. Unless they are used in #ifdef
.
Note: identifiers starting with underscore and upper case letters are reserved in C99. Use code is not allowed to use them.
Note: prefer to use standard uint32_t
from stdint.h
instead of user defined types.