1

I was trying to create and initialize a struct using a variable length macro. I want to be able create/initialize the struct with '0's and then initialize some fields of the struct with values that were optionally passed in.

Is this possible to do? I was trying the following:

#define INIT_ENTRY(x, ...) \
    entry_t x = {.id = 0, .age = 0} \
    x.id  = <I want to use arg1 here>
    x.age = <i want to use arg2 here if it exists> 

Is there a way to accomplish this?

1
  • Would something like the following use-case meet your need: x = INIT_ENTRY(x, 1) would do about (entry_t){.id = 1} and x = INIT_ENTRY(x, 1, 2) would do about (entry_t){.id = 1, .age = 2} ? What is the max length needed - arbitrary? BTW: x.id = <I want to use arg1 here> is not initialization, but assignment. Commented Aug 18, 2017 at 21:50

2 Answers 2

1

It can be done with a combination of argument counting and concatenation.

  1. First you need a macro that counts it's arguments, which I'll call NARGS This was asked and answered here. Note that answers are compiler-dependent.

  2. Next you need a series of macros for all specific cases:

    #define INIT_ENTRY_0(x) entry_t x = {.id = 0, .age = 0}
    #define INIT_ENTRY_1(x, _id) entry_t x = {.id = _id, .age = 0}
    #define INIT_ENTRY_2(x, _id, _age) entry_t x = {.id = _id, .age = _age}

  3. You also need a concatenation macro:

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

  4. Last, use concatenation to choose the correct one:

    #define INIT_ENTRY(x, ...) CONCAT(INIT_ENTRY_, NARGS(__VA_ARGS__))(x, #__VA_ARGS__)

Sign up to request clarification or add additional context in comments.

Comments

0

If you keep the same order of initializers in your macro as in your initialization list, then given you're always initializing everything else to 0, you can simply do this:

#define _INIT_ENTRY_UTILITY(x, ID_, AGE_, ...) \
   entry_t x = {.id = ID_, .age = AGE_}
#define INIT_ENTRY(...) _INIT_ENTRY_UTILITY(__VA_ARGS__, 0, 0, )

I assume your real use case has more than 2 parameters; if you take this approach, make sure to mimic its form exactly to maintain portability. In particular:

  • Changing to #define INIT_ENTRY(x, ...) for "clarity" will break calls that look like INIT_ENTRY(foo) on standard C preprocessors. What's worse is that it will actually work on some popular cpp's (such as gnu) that support such things as an extension, so the portability issue's hidden.
  • Removing the final comma in the call to _INIT_ENTRY_UTILITY from INIT_ENTRY's replacement list leads to the same portability issue

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.