I know what the message means, but not why it happened.
main.c:26:2: error: initializer element is not constant
rgb24_xrgb(0xB14835), // brick red
My code:
typedef uint32_t rgb24_t;
// Color structure
typedef struct {
uint8_t r;
uint8_t g;
uint8_t b;
} xrgb_t;
// Table of colors
const xrgb_t COLORS[] = {
rgb24_xrgb(0xB14835), // brick red
rgb24_xrgb(0x4C1661), // indigo
rgb24_xrgb(0xA3268E), // royal purple
};
Here are my macros:
#define xrgb(rr, gg, bb) ((xrgb_t) { .r = ((uint8_t)(rr)), .g = ((uint8_t)(gg)), .b = ((uint8_t)(bb)) })
#define rgb24_r(c) ((((rgb24_t) (c)) >> 16) & 0xFF)
#define rgb24_g(c) ((((rgb24_t) (c)) >> 8) & 0xFF)
#define rgb24_b(c) ((((rgb24_t) (c)) >> 0) & 0xFF)
#define rgb24_xrgb(c) xrgb(rgb24_r(c), rgb24_g(c), rgb24_b(c))
The preprocessor output is here:
const xrgb_t COLORS[] = {
((xrgb_t) { .r = ((uint8_t)(((((rgb24_t) (0xB14835)) >> 16) & 0xFF))), .g = ((uint8_t)(((((rgb24_t) (0xB14835)) >> 8) & 0xFF))), .b = ((uint8_t)(((((rgb24_t) (0xB14835)) >> 0) & 0xFF))) }),
((xrgb_t) { .r = ((uint8_t)(((((rgb24_t) (0x4C1661)) >> 16) & 0xFF))), .g = ((uint8_t)(((((rgb24_t) (0x4C1661)) >> 8) & 0xFF))), .b = ((uint8_t)(((((rgb24_t) (0x4C1661)) >> 0) & 0xFF))) }),
((xrgb_t) { .r = ((uint8_t)(((((rgb24_t) (0xA3268E)) >> 16) & 0xFF))), .g = ((uint8_t)(((((rgb24_t) (0xA3268E)) >> 8) & 0xFF))), .b = ((uint8_t)(((((rgb24_t) (0xA3268E)) >> 0) & 0xFF))) })
};
Looks fairly constant to me.
Where is the problem?
From C11 6.7.9/4 (C99 had similar text):
All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.
From C11 6.6 "Constant expressions":
More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:
- an arithmetic constant expression,
- a null pointer constant,
- an address constant, or
- an address constant for a complete object type plus or minus an integer constant expression.
A compound literal is none of those bullet points, so it is not permitted in an initializer.
I don't see any rationale as to why it is not permitted, if the compound literal's initializers are all constant expressions that meet these criteria.
However you can work around this by just using the initializers without the compound literal:
const xrgb_t COLORS[] = {
{ .r = ........... , .g = ............., .b = ........ },
{ .r = ....... // etc.
};
This should be easy to do in your existing code by renaming your macro to just give the { }
part, and then have another macro with the original name that does (const xrgb_t) rgb24_xrgb(X)
to make the compound literal, or whatever.
NB. Making the compound literal const
lets the compiler store it in read-only area.