Reputation: 19554
In C, is there a nice way to track the number of elements in an enum? I've seen
enum blah {
FIRST,
SECOND,
THIRD,
LAST
};
But this only works if the items are sequential and start at zero.
Upvotes: 57
Views: 104068
Reputation: 345
Well, this is very old, but I have found a method not mentioned here.
Most compilers provided the __COUNTER__
macro. This macro initially expands to 0, and whenever it is used it adds 1 to itself. It is reset at the beginning of object files. This means that you can write this:
#include <stdio.h>
const int TestSizeInitial = __COUNTER__;
typedef enum {
TEST_0 = __COUNTER__,
TEST_1 = __COUNTER__,
TEST_2 = __COUNTER__
} Test;
const int TestSize = __COUNTER__ - TestSizeInitial - 1;
const int TestSizeInitial2 = __COUNTER__;
typedef enum {
TEST2_0 = __COUNTER__,
TEST2_1 = __COUNTER__,
TEST2_2 = __COUNTER__,
TEST2_3 = __COUNTER__
} Test2;
const int TestSize2 = __COUNTER__ - TestSizeInitial2 - 1;
int main()
{
printf("Number of Test variants = %i\n", TestSize);
printf("Number of Test2 variants = %i\n", TestSize2);
printf("TEST_0 = %i\n", TEST_0);
printf("TEST_1 = %i\n", TEST_1);
printf("TEST_2 = %i\n", TEST_2);
printf("TEST2_0 = %i\n", TEST2_0);
printf("TEST2_1 = %i\n", TEST2_1);
printf("TEST2_2 = %i\n", TEST2_2);
printf("TEST2_3 = %i\n", TEST2_3);
return 0;
}
This will print:
Number of Test variants = 3
Number of Test2 variants = 4
TEST_0 = 1
TEST_1 = 2
TEST_2 = 3
TEST2_0 = 6
TEST2_1 = 7
TEST2_2 = 8
TEST2_3 = 9
This has the advantage of not having the last variant used as counter, which can mess up switch statements. The downside is that, as you can see, it makes it very hard to reason about the actual value of the enum variants. As long as you don't need their explicit value, you're fine. For example, if you place Test
in, say test.h
, and Test2
in test2.h
, the order with which you call the include statements changes the value of the enum variants. It does not change the value of TestSize
and TestSize2
because they are defined in terms of the difference with the initial value of __COUNTER__
.
Upvotes: 0
Reputation: 19
#include <stdio.h>
// M_CONC and M_CONC_ come from https://stackoverflow.com/a/14804003/7067195
#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B
#define enum_count_suffix _count
#define count(tag) M_CONC(tag, enum_count_suffix)
#define countable_enum(tag, ...) \
enum tag {__VA_ARGS__}; \
const size_t count(tag) = sizeof((int []) {__VA_ARGS__}) / sizeof(int)
// The following declares an enum with tag `color` and 3 constants: `red`,
// `green`, and `blue`.
countable_enum(color, red, green, blue);
int main(int argc, char **argv) {
// The following prints 3, as expected.
printf("number of elements in enum: %d\n", count(color));
}
Upvotes: 1
Reputation: 879
I know this is a very old question, but as the accepted answer is wrong, I feel compelled to post my own. I'll reuse the accepted answer's example, slightly modified. (Making the assumption that enums are sequential.)
// Incorrect code, do not use!
enum blah {
FIRST = 0,
SECOND, // 1
THIRD, // 2
END // 3
};
const int blah_count = END - FIRST;
// And this above would be 3 - 0 = 3, although there actually are 4 items.
Any developer knows the reason: count = last - first + 1
.
And this works with any combination of signs (both ends negative, both positive, or only first end negative). You can try.
// Now, the correct version.
enum blah {
FIRST = 0,
SECOND, // 1
THIRD, // 2
END // 3
};
const int blah_count = END - FIRST + 1; // 4
Edit: reading the text again, I got a doubt. Is that END
meant not to be part of the offered items? That looks weird to me, but well, I guess it could make sense...
Upvotes: 6
Reputation: 5536
Old question, I know. This is for the googlers with the same question.
You could use X-Macros
Example:
//The values are defined via a map which calls a given macro which is defined later
#define ENUM_MAP(X) \
X(VALA, 0) \
X(VALB, 10) \
X(VALC, 20)
//Using the map for the enum decl
#define X(n, v) [n] = v,
typedef enum val_list {
ENUM_MAP(X) //results in [VALA] = 0, etc...
} val_list;
#undef X
//For the count of values
#define X(n, v) + 1
int val_list_count = 0 + ENUM_MAP(X); //evaluates to 0 + 1 + 1 + 1
#undef X
This is also transparent to an IDE, so auto-completes will work fine (as its all done in the pre-processor).
Upvotes: 37
Reputation: 1801
If you don't assign your enums you can do somethings like this:
enum MyType {
Type1,
Type2,
Type3,
NumberOfTypes
}
NumberOfTypes will evaluate to 3 which is the number of real types.
Upvotes: 87
Reputation: 49
int enaumVals[] =
{
FIRST,
SECOND,
THIRD,
LAST
};
#define NUM_ENUMS sizeof(enaumVals) / sizeof ( int );
Upvotes: 3
Reputation: 881583
Well, since enums can't change at run-time, the best thing you can do is:
enum blah {
FIRST = 7,
SECOND = 15,
THIRD = 9,
LAST = 12
};
#define blahcount 4 /* counted manually, keep these in sync */
But I find it difficult to envisage a situation where that information would come in handy. What exactly are you trying to do?
Upvotes: 3
Reputation: 332866
I don't believe there is. But what would you do with such a number if they are not sequential, and you don't already have a list of them somewhere? And if they are sequential but start at a different number, you could always do:
enum blah {
FIRST = 128,
SECOND,
THIRD,
END
};
const int blah_count = END - FIRST;
Upvotes: 45