Some Name
Some Name

Reputation: 9521

Escape struct field in a macro definition

I have the following structure (simplified):

struct error_t{
    const char *file;
    const char *error_desc;
};

I wrote a macro to create the structure

#define ERROR_SET(error_desc) \
{ \
   struct error_t tmp = {.error_desc = error_desc, .file = __FILE__}; \
   struct error_t *ptr = malloc(sizeof(*ptr)); \
   memcpy(ptr, &tmp, sizeof(tmp)); \
   *error_ptr = ptr; \
}

The problem is that at the line

struct error_t tmp = {.error_desc = error_desc, .file = __FILE__}

both error_descs .error_desc = error_desc are replaced which is not what I wanted. The only solution I can see is to rename the macro function parameter from error_desc to _error_desc, but maybe there is a better way. Maybe we can sort of "escape" the error_desc to be substituted in the .error_desc?

Upvotes: 0

Views: 149

Answers (3)

0___________
0___________

Reputation: 67546

Just do not use the same name for the parameter and the struct member

Upvotes: 3

AnT stands with Russia
AnT stands with Russia

Reputation: 320491

You can "deceive" the preprocessor with something like

#define CONCAT(a, b) a##b

#define ERROR_SET(error_desc) \
{ \
   struct error_t tmp = { .CONCAT(error,_desc) = error_desc, .file = __FILE__ }; \
   ...\
}

but it is just not worth it. Just rename the parameter. And develop a convention for parameter naming that would help you to avoid such naming conflicts in the future.


On the second thought, the extra CONCAT macro is not even necessary. This will achieve the same objective

#define ERROR_SET(error_desc) \
{ \
   struct error_t tmp = { .error##_desc = error_desc, .file = __FILE__ }; \
   ...\
}

Upvotes: 1

P.W
P.W

Reputation: 26800

You can have a different MACRO that the preprocessor would replace as error_desc.

#define ERROR_DESC error_desc

Then you can define ERROR_SET like this:

#define ERROR_SET(error_desc) \
{ \
   struct error_t tmp = {.ERROR_DESC = error_desc, .file = __FILE__}; \
   struct error_t *ptr = malloc(sizeof(*ptr)); \
   memcpy(ptr, &tmp, sizeof(tmp)); \
   *error_ptr = ptr; \
}

This works because the substitution is done only once.

Upvotes: 2

Related Questions