Reputation: 814
I have an array of color codes, the size of which is known at compile time. I want to declare another array of the same size. But the code below throws an error.
I can, of course, declare the size as a global constant and then use that in the declaration of both arrays. But I don't want to keep adjusting the size constant when I add new colors. Is there a way to do this? (The variables are global.)
static const char *colors[] = {"#0000ff",
"#00ff00",
"#ff0000",
"#ffff00",
"#ff00ff",
"#00ffff",
"#ffffff",
"#000000",
"#ff8040",
"#c0c0c0",
"#808080",
"#804000"};
static const int NUM_COLORS = sizeof(colors) / sizeof(colors[0]);
static ColorButtons color_buttons[NUM_COLORS];
Upvotes: 4
Views: 165
Reputation: 214300
Just to yet again propagate for X-macros - this is a perfect task for them. All you need to do is to maintain an X macro list at the top and then you can have string literals, values, item counting, look-up tables etc etc all at compile time. Quite powerful and maintainable, but at the expensive of readability for those not used at reading X macro code.
Example:
#include <stdio.h>
#include <stdint.h>
#define COLOR_LIST(X) \
/* index val */ \
X(0, 0000ff) \
X(1, 00ff00) \
X(2, ff0000) \
/* declare an array of strings with a certain format: */
#define COLOR_STRING(index, val) [index] = "#" #val,
static const char *color_str[] = { COLOR_LIST(COLOR_STRING) };
/* declare an enum to translate indices to values: */
#define COLOR_ENUM(index, val) color_##index = 0x##val,
typedef enum : uint32_t
{
COLOR_LIST(COLOR_ENUM)
} color_t;
/* declare an enum for the sole purpose of counting items: */
#define COLOR_COUNT(index, val) color_count_##index,
typedef enum
{
COLOR_LIST(COLOR_COUNT)
NUM_COLORS
} color_count_t;
int main()
{
printf("Total colors: %d\n", NUM_COLORS);
printf("[0] string: %s value: %.6X\n", color_str[0], color_0);
printf("[1] string: %s value: %.6X\n", color_str[1], color_1);
printf("[2] string: %s value: %.6X\n", color_str[2], color_2);
// ...or if you will
#define COLOR_PRINT(index,val) printf("[" #index "] string: %s value: %.6X\n", color_str[index], color_##index);
COLOR_LIST(COLOR_PRINT)
}
Output:
Total colors: 3
[0] string: #0000ff value: 0000FF
[1] string: #00ff00 value: 00FF00
[2] string: #ff0000 value: FF0000
Upvotes: 2
Reputation: 311048
In C opposite to C++ variables with the qualifier const
are not part of compile-time constant expressions. And you may not define a variable length array with static storage duration either in a file scope or in a block scope with storage class specifier static
.
Instead you could write for example
static enum { NUM_COLORS = sizeof(colors) / sizeof(colors[0]) };
static ColorButtons color_buttons[NUM_COLORS];
Another approach is the following
static ColorButtons color_buttons[sizeof(colors) / sizeof(colors[0])];
static const size_t NUM_COLORS = sizeof(colors) / sizeof(colors[0]);
though there are two times used the expression sizeof(colors) / sizeof(colors[0])
.
Or if your compiler supports C23 then
constexpr size_t NUM_COLORS = sizeof(colors) / sizeof(colors[0]);
static ColorButtons color_buttons[NUM_COLORS];
Upvotes: 8
Reputation: 2063
To add to the previous answers:
#define ARRAY_SIZE(X) (sizeof X / sizeof X[0])
It's reusable also.
If you are not sure whether your array has any elements (aka can be a null pointer), you can return 0 in this case:
#define ARRAY_SIZE(X) (X == NULL ? 0 : sizeof X / sizeof X[0])
int full[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int* empty = NULL;
printf("full size = %u\n", ARRAY_SIZE(full)); // 10
printf("empty size = %u\n", ARRAY_SIZE(empty)); // 0
Upvotes: 2
Reputation: 224387
The size of a file scope array, if specified, must be an integer constant expression. A variable qualified with const
does not qualify as such as expression (this differs from C++ which does allow this).
Instead of making NUM_COLORS
a variable, make it a preprocessor symbol:
#define NUM_COLORS (sizeof(colors) / sizeof(colors[0]))
The expression that this expand to is an integer constant expression, and can therefore be used as the size of an array.
The only thing you'll need to look out for is to make sure you don't redefine colors
at a lower scope where you would also use NUM_COLORS
.
Upvotes: 7
Reputation: 67721
static const int NUM_COLORS
- const
variables are not constant expressions required as size of the static storage duration arrays.
You need to create a macrodefintion:
#define NUM_COLORS (sizeof(colors) / sizeof(colors[0]))
Upvotes: 3