Some `enum` tricks
On 2017/10/12 at 00:00
After delving into some C projects, I found the usage of enum
is more powerful than I used to think. Here are some
interesting tricks I learned.
Get the number of elements in a enum
type
The need for getting the number of elements in a enum
type is common. For example, enum nf_ct_ext_id
is defined in linux kernel to specify the type of conntrack extension being used. We may need to know how many extensions are defined in the kernel. So adding the NF_CT_EXT_NUM
at the end of the enum
can do the job immediately. And adding or removing extention type in the enum
will change the value of NF_CT_EXT_NUM
automatically.
enum nf_ct_ext_id {
NF_CT_EXT_HELPER,
NF_CT_EXT_NAT,
NF_CT_EXT_SEQADJ,
NF_CT_EXT_ACCT,
NF_CT_EXT_TSTAMP,
NF_CT_EXT_NUM,
};
Using enum
to define constants
The first look at enum ip_conntrack_status
is a little overwhelming for me. After digging into the code, I found the use of enum ip_conntrack_status
is for defining constant. The kernel does not use enum ip_conntrack_status
as a type directly (You can found the references to the type is none.). And you can also find a lot of projects use untagged enum to define constant. The following code snippet is from iptable project.
enum {
O_SET_MARK = 0,
O_AND_MARK,
O_OR_MARK,
O_XOR_MARK,
O_SET_XMARK,
F_SET_MARK = 1 << O_SET_MARK,
F_AND_MARK = 1 << O_AND_MARK,
F_OR_MARK = 1 << O_OR_MARK,
F_XOR_MARK = 1 << O_XOR_MARK,
F_SET_XMARK = 1 << O_SET_XMARK,
F_ANY = F_SET_MARK | F_AND_MARK | F_OR_MARK |
F_XOR_MARK | F_SET_XMARK,
};
The discussion for using enum
to define constants can be found in the following links.
To me, the most compelling reasons are
- The constants defined in the same
enum
can be thought as in the same group - Constants defined in a
enum
have a symbol in the debugger's symbol table
sizeof(enum_type) == sizeof(int)
which may not be acceptable for some applications
Although using enum
to define a new type is common, but in most compiler the size of a enum
type is the same as an integer. In some memory limited application, we may want the limit the size of enum type.
In C++11, we can bind the enum type to a existing type. For example:
enum Color : unsigned char {
Red,
Blue,
Yellow
};
However, in C we don't have this kind of priviledge. I found some code use untagged enum to define constants and assign it to the smaller size variable. For example:
enum {
XT_CONNMARK_SET = 0,
XT_CONNMARK_SAVE,
XT_CONNMARK_RESTORE
};
struct xt_connmark_tginfo1 {
__u32 ctmark, ctmask, nfmask;
__u8 mode;
};
The __u8 mode
is used the save one of XT_CONNMARK_SET
, XT_CONNMARK_SAVE
, XT_CONNMARK_RESTORE
. Instead of using the enum
type directly, this example use only one byte to save the mode.