Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the need of defining an Enum/Struct by way of macros?

I am referring to a code sample from the opensource project tig. Which is a great tool!

file:tig.c

I am struggling to find a reason for defining the request enumeration 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 as well..

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 can be seen REQ_GROUP has been #defined multiple times creating confusion.. atleast to me. Well i know there might be a good reason to do as such.. what is the actual reason to hide the enum/struct definition in the code using macros?

like image 492
ashishsony Avatar asked Feb 13 '13 12:02

ashishsony


2 Answers

This is usually down when different treatment should be used on the same data source.

For example, you might do:

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

And then:

enum MyEnum {
# define X(e) e,

  MY_LIST

  Last

# undef X
};

In which case, MY_LIST is expanded using the current definition of X.

Now, in the same file, I can also use MY_LIST to create a 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

This way, the set of values of the enum is only ever written once, and automatically both the enum and a number of methods dealing with it are kept in sync with this set.

like image 124
Matthieu M. Avatar answered Nov 10 '22 23:11

Matthieu M.


It's to avoid duplication of the list of requests. That list only needs maintaining in one place, the definition of REQ_INFO, and the enumeration and data structures are automatically generated from that list by suitable definitions of REQ_GROUP and REQ_.

Without those macros, the enumeration and the data structure would have to be maintained separately, taking care to keep them consistent with each other, involving more work and more scope for error.

like image 40
Mike Seymour Avatar answered Nov 10 '22 23:11

Mike Seymour