What is the need to define Enum / Struct with macros?

I mean the sample code from the open source project tig . This is a great tool!

File: tig.c

I am struggling to find a reason to determine the enumeration of the request as follows:

enum request { #define REQ_GROUP(help) #define REQ_(req, help) REQ_##req /* Offset all requests to avoid conflicts with ncurses getch values. */ REQ_UNKNOWN = KEY_MAX + 1, REQ_OFFSET, REQ_INFO, /* Internal requests. */ REQ_JUMP_COMMIT, #undef REQ_GROUP #undef REQ_ }; 

even structures.

 static const struct request_info req_info[] = { #define REQ_GROUP(help) { 0, NULL, 0, (help) }, #define REQ_(req, help) { REQ_##req, (#req), STRING_SIZE(#req), (help) } REQ_INFO #undef REQ_GROUP #undef REQ_ }; 

as you can see, REQ_GROUP has repeatedly been #defined, creating confusion .. at least for me. Well, I know there can be good reasons for this. What is the actual reason to hide the enum / struct definition in code with macros?

+7
source share
3 answers

This usually happens when using a different method in the same data source.

For example, you can:

 #define MY_LIST X(Elem1) X(Elem2) X(Elem3) 

And then:

 enum MyEnum { # define X(e) e, MY_LIST Last # undef X }; 

In this case, MY_LIST expanded using the current definition of X

Now, in the same file, I can also use MY_LIST to create the to_string method

 char const* to_string(MyEnum e) { switch(e) { # define X(e) case e: return #e; MY_LIST case Last: return "Last"; # undef X } return 0; } // to_string 

Thus, a set of enumeration values ​​is recorded only once, and automatically both the enumeration and a number of methods associated with it are stored in synchronization with this set.

+7
source

To avoid duplicate query list. This list only requires support in one place, the definition of REQ_INFO , and enumeration and data structures are automatically generated from this list by the appropriate definitions of REQ_GROUP and REQ_ .

Without these macros, the enumeration and data structure must be maintained separately, ensuring that they are consistent with each other, including more work and more potential for errors.

+1
source

You missed important definitions in the same file:

 #define REQ_INFO \ REQ_GROUP("View switching") \ VIEW_INFO(VIEW_REQ), \ \ REQ_GROUP("View manipulation") \ REQ_(ENTER, "Enter current line and scroll"), \ REQ_(NEXT, "Move to next"), \ REQ_(PREVIOUS, "Move to previous"), \ < output omitted as it is too long > 

So, for example, the structure you showed is expanded:

 static const struct request_info req_info[] = { { 0, NULL, 0, "View switching" }, < VIEW_INFO also expands to some long structure that was ommited here > { 0, NULL, 0, "View manipulation" }, { REQ_ENTER, ENTER, STRING_SIZE("ENTER"), "Enter current line and scroll"}, { REQ_NEXT, NEXT, STRING_SIZE("NEXT"), "Move to next"} < and so on > }; 

As mentioned in other answers, this is mainly done to synchronize multiple structures / counters.

+1
source

All Articles