0

So I had this query wherein say I have an enum and a struct that look like these,

enum fields {
   field_1,
   field_2
};

struct my_struct {
    int field_1;
    int field_2;
};

My specific need is, given the enum with the names of the structure members (field_1, field_2 etc) I should be able to generate a macro which can set the structure member to a given value.

#define my_macro (__a, __field) \
__a.__field = 1;

So is there a way to call my_macro like this:

struct my_struct b;
/* extract members of enum as string literals  */
my_macro(b, /*field name from the enum */);

Few other posts detailing usage of boost macros helps me extract the enum members as strings ( How to convert an enum type variable to a string?). Issue is with passing it in the appropriate manner to the macro.

Community
  • 1
  • 1
  • 1
    Well, did you try it? – this Jul 09 '15 at 01:08
  • 2
    Please select one language: C or C++. – too honest for this site Jul 09 '15 at 01:15
  • 1
    Macros are evaluated and expanded at compile-time only. If I am reading your question correctly, you are asking for something that is determined at runtime instead. In which case, a macro will not work. You need another solution, such as a `std::map` containing pointers to functions that know how to read/write the individual structure fields as needed. – Remy Lebeau Jul 09 '15 at 01:15
  • What are you trying to solve? I think there may be a better way using the language instead of a macro. – Steve Jul 09 '15 at 01:15
  • @RemyLebeau: That will not work in C. – too honest for this site Jul 09 '15 at 01:16
  • @Olaf: a `std::map` will clearly not work in C, but a plain array of name+pointer pairs will. – Remy Lebeau Jul 09 '15 at 01:20
  • @RemyLebeau: You mean implementing a map as a module? Sure, but I think OP should first clarify which language he actually targets. – too honest for this site Jul 09 '15 at 01:22
  • @Olaf : Apologies for the confusion in choice of language. C++ is fine, was hoping a solution that I'm unaware of might exist that could work with C too. – simon_says Jul 09 '15 at 01:34
  • 1
    @simon_says: You should forget about that. While you **can** program C-like in C++, you actually should not. And even similar syntax might have subtle differences which can make debugging very difficult. – too honest for this site Jul 09 '15 at 01:36
  • @RemyLebeau: Regarding the first point you made, boost macros like BOOST_PP_STRINGIZE will be evaluated/expanded at compile time itself. So I was looking at using the info from these macros to achieve what I needed to do in my_macro, thus not having to bother with determination at run-time. (Have posted similar comment under Havenard's post) – simon_says Jul 09 '15 at 02:38

2 Answers2

1

It should work the way it is. Macros are processed before compilation, while the code is still code, and they result in code generation.

Your macro #define my_macro(__a, __field) __a.__field = 1; will cause any entry like my_macro(x, y) to be transformed into x.y = 1;, literally, before its handed to the compiler.

If you do something like my_macro(1+1, "test"), it will generate the code 1+1."test" = 1; and will create a compile error. Thats how simple macros are.

Thats why macro parameters are often enclosed by () to make sure it will work the way it was intented, if you don't do that things like this can happen:

#define div_by_100(a) a / 100

printf("%d\n", div_by_100(1000)); // will print 10
printf("%d\n", div_by_100(500 + 500)); // will print 505

This happens because order of operations is resolved at compile time, after the macros have been resolved.

Notice that, because macros are resolved before compilation, they are not a runtime solution. If this enum value is not explict in the code, macros won't help you at all. You will have to write a routing function that will assign a value to each member of this class/struct depending on what enum value was given. Example:

void route(struct farm* s, enum animals e)
{
    switch (e)
    {
        case cow:
            s->cow = 1;
            break;
        case duck:
            s->duck = 1;
            break;
        case horse:
            s->horse = 1;
            break;
        case goat:
            s->goat = 1;
            break;
    }
}
Havenard
  • 27,022
  • 5
  • 36
  • 62
  • Just wondering if there is a way to pass output of one macro as-is to another macro. So in the example in the question, could output of BOOST_PP_STRINGIZE(field_1) be used to pass as parameter to my_macro? – simon_says Jul 09 '15 at 02:07
  • @simon_says You can pass a macro as parameter to another, no point in doing that in this case though. All this macro does is `#define BOOST_PP_STRINGIZE(x) #x`, which converts `x` into `"x"`. You can use the same resource in your macro, but converting it to a string wont make it magically work, in fact it wont even compile. – Havenard Jul 09 '15 at 02:11
0

It depends on the way your mechanism of turning an enum to a string works. Your macro should work as long as that mechanism is still a macro that gets replaced by the preprocessor. That's the issue. Your macro should otherwise work properly.

José Tomás Tocino
  • 9,873
  • 5
  • 44
  • 78