Find the number of elements in an enumerated type?

D

David Mathog

Is there a standard compliant method to access the number of elements in
an enumerated type in C, either from within the preprocessor or the
running program?

The example below compiles and runs but returns 4 twice (the number of
bytes used to store a value in test) when the needed answer is 5 (the
number of enumerated values in atype).

#include <stdlib.h>
#include <stdio.h>
enum atype {ZERO,ONE,TWO,THREE,FOUR};
int main(void){
enum atype test;
(void) fprintf(stdout,"1: %d\n",sizeof(test));
(void) fprintf(stdout,"2: %d\n",sizeof(enum atype));
(void) exit(EXIT_SUCCESS);
}

One could insert

#define TESTN 5

after the enum statement, and use that, but it still requires the
programmer to count the number of elements, as opposed to having the
computer do it.

Maybe I'm assuming too much. Doesn't the C standard say that the enum
statement, without any "=" within the {}, always assigns the enumerated
values as 0,1,2,3,4? Seems like there should be a way to get the
preprocessor or run time to cough up the number of elements.

I did come up with this method, which will work so long as the special
last element is never displaced from it's position at the end of the
list. It is kind of hideous though:

#include <stdlib.h>
#include <stdio.h>
enum atype {ONE,TWO,THREE,FOUR,FIVE, I_AM_ALWAYS_LAST};
int main(void){
enum atype test;
test = I_AM_ALWAYS_LAST ;
(void) fprintf(stdout,"%d\n",test);
(void) exit(EXIT_SUCCESS);
}


Thanks,

David Mathog
 
I

Ian Collins

David said:
Is there a standard compliant method to access the number of elements in
an enumerated type in C, either from within the preprocessor or the
running program?

The example below compiles and runs but returns 4 twice (the number of
bytes used to store a value in test) when the needed answer is 5 (the
number of enumerated values in atype).
No.

If you must know (which is probably rare), add a known last element.
Even that only works if the values are contiguous and start form 0.
 
B

borophyll

Is there a standard compliant method to access the number of elements in
an enumerated type in C, either from within the preprocessor or the
running program?

Not directly, but you could declare enums in the following way, using
some preprocessing magic:

#include <stdlib.h>
#include <stdio.h>
#define ENUM_START(type) enum type {
#define ENUMCONCAT(type) I_AM_ALWAYS_LAST_ ## type
#define ENUM_END(type) ENUMCONCAT(type) };
#define ENUM_SIZE(type) ENUMCONCAT(type)

ENUM_START(atype)
ONE,
TWO,
THREE,
FOUR,
FIVE,
ENUM_END(atype)

int main(void)
{
enum atype atest = ENUM_SIZE(atype);
(void) fprintf(stdout,"%d\n",atest);
(void) exit(EXIT_SUCCESS);

}
 
C

*coffee*

Not directly, but you could declare enums in the following way, using
some preprocessing magic:

#include <stdlib.h>
#include <stdio.h>
#define ENUM_START(type) enum type {
#define ENUMCONCAT(type) I_AM_ALWAYS_LAST_ ## type
#define ENUM_END(type) ENUMCONCAT(type) };
#define ENUM_SIZE(type) ENUMCONCAT(type)

ENUM_START(atype)
ONE,
TWO,
THREE,
FOUR,
FIVE,
ENUM_END(atype)

int main(void)
{
enum atype atest = ENUM_SIZE(atype);
(void) fprintf(stdout,"%d\n",atest);
(void) exit(EXIT_SUCCESS);

Nice. BUT this way we couldn't assign the value in ENUM.
It's difficult to me.



--coffee
 
R

Richard Tobin

#define ENUMCONCAT(type) I_AM_ALWAYS_LAST_ ## type
#define ENUM_END(type) ENUMCONCAT(type) };
#define ENUM_SIZE(type) ENUMCONCAT(type)

I have often used the manual version of this - inserting an extra
item in the enumeration. It has the minor disadvantage that some
compilers (such as gcc) will give a warning about a missing value
in switch statements that cover all the real values.

-- Richard
 
T

Thad Smith

David said:
Is there a standard compliant method to access the number of elements in
an enumerated type in C, either from within the preprocessor or the
running program?

The example below compiles and runs but returns 4 twice (the number of
bytes used to store a value in test) when the needed answer is 5 (the
number of enumerated values in atype).

#include <stdlib.h>
#include <stdio.h>
enum atype {ZERO,ONE,TWO,THREE,FOUR};
int main(void){
enum atype test;
(void) fprintf(stdout,"1: %d\n",sizeof(test));
(void) fprintf(stdout,"2: %d\n",sizeof(enum atype));
(void) exit(EXIT_SUCCESS);
}

One could insert

#define TESTN 5

after the enum statement, and use that, but it still requires the
programmer to count the number of elements, as opposed to having the
computer do it.

Maybe I'm assuming too much. Doesn't the C standard say that the enum
statement, without any "=" within the {}, always assigns the enumerated
values as 0,1,2,3,4? Seems like there should be a way to get the
preprocessor or run time to cough up the number of elements.

I did come up with this method, which will work so long as the special
last element is never displaced from it's position at the end of the
list. It is kind of hideous though:

#include <stdlib.h>
#include <stdio.h>
enum atype {ONE,TWO,THREE,FOUR,FIVE, I_AM_ALWAYS_LAST};
int main(void){
enum atype test;
test = I_AM_ALWAYS_LAST ;
(void) fprintf(stdout,"%d\n",test);
(void) exit(EXIT_SUCCESS);
}

I use your method, David:
enum eModulation {
EM_FM, EM_AM, EM_CM, EM_NUM_MODS};
 
C

CBFalconer

Richard said:
I have often used the manual version of this - inserting an extra
item in the enumeration. It has the minor disadvantage that some
compilers (such as gcc) will give a warning about a missing value
in switch statements that cover all the real values.

So simply write a suitable switch statement:

switch (enumval) {
case ONE: ...
...
case FOUR: ...
default: fputs("Invalid enumval encountered\n", stderr;
}

or whatever error catching mechanism you prefer.
 
R

Richard Tobin

I have often used the manual version of this - inserting an extra
item in the enumeration. It has the minor disadvantage that some
compilers (such as gcc) will give a warning about a missing value
in switch statements that cover all the real values.
[/QUOTE]
So simply write a suitable switch statement:
default: fputs("Invalid enumval encountered\n", stderr;

Yes, of course you can do that. But (a) it's annoying to have to do
it in dozens of places, (b) it's putting in code to handle a case that
should never happen, just to shut the compiler up, and (c) it
suppresses the warning when you really have made an error.

-- Richard
 
C

CBFalconer

Richard said:
Yes, of course you can do that. But (a) it's annoying to have to do
it in dozens of places, (b) it's putting in code to handle a case that
should never happen, just to shut the compiler up, and (c) it
suppresses the warning when you really have made an error.

Please do not strip attributions for material you quote.

No, it's not useless. enum objects can hold any value, they are
not limited to the actually specified set. If one gets into your
system you want to know about it soonest. Without the default the
value is just ignored, which may not be a viable resolution.
 
B

borophyll

Nice. BUT this way we couldn't assign the value in ENUM.
It's difficult to me.

--coffee

Sorry, yes I should have stated that you can only use this if the
constants are contiguous and begin with 0, but I figured this would be
clear from Ian's post.

Regards,
B.
 
R

Richard Tobin

Yes, of course you can do that. But (a) it's annoying to have to do
it in dozens of places, (b) it's putting in code to handle a case that
should never happen, just to shut the compiler up, and (c) it
suppresses the warning when you really have made an error.
[/QUOTE]
No, it's not useless.

I didn't say anything about it being useless to check values.
enum objects can hold any value, they are
not limited to the actually specified set. If one gets into your
system you want to know about it soonest. Without the default the
value is just ignored, which may not be a viable resolution.

Of course. But I don't want to put in code to check it all over the
place, any more than I constantly check my pointers in case they have
suddenly taken on bogus values.

-- Richard
 
R

Roberto Waltman

David said:
Is there a standard compliant method to access the number of elements in
an enumerated type in C, either from within the preprocessor or the
running program?

Not counting the alreaddy discussed special case of all enum values
being contiguous (not necessarily starting at zero,) the only way I
see is by duplicating the list thus:

enum atype {ZERO,ONE,TWO,THREE,FOUR};
enum atype all_atypes[] = {ZERO,ONE,TWO,THREE,FOUR};
#define NUM_ATYPE (sizeof(all_atypes)/sizeof(enum atype))

This would work for any values, (for example, enum atype
{ZERO=0x01,ONE=0x02,TWO=0x04,THREE=0x08,FOUR=0x10}; )
but I wouldn't like to do this if the number of values declared in a
single enum is large.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top