0

I have concrete_impl.h (as is):

#ifdef TUPLE_ITERATOR_WITH_INDEX
    #define TUPLE_ITERATOR TUPLE_ITERATOR_NO_INDEX
    #define iterate_tuple_fname iterate_tuple_id
#else
    #define TUPLE_ITERATOR TUPLE_ITERATOR_INDEX
    #define iterate_tuple_fname iterate_tuple
#endif

#undef  iterate_tuple_fname_back
#define iterate_tuple_fname_back iterate_tuple_fname##_back

static void iterate_tuple_fname()         // ok 
{
}

static void iterate_tuple_fname_back()   // redefinition error
{
}

And concrete.h (as is):

#ifndef CONCRETE_H
#define CONCRETE_H

#define TUPLE_ITERATOR_WITH_INDEX
#include "concrete_impl.h"

#undef TUPLE_ITERATOR_WITH_INDEX
#include "concrete_impl.h"


#endif // CONCRETE_H

What I want to get - is 4 functions:

  • iterate_tuple
  • iterate_tuple_id
  • iterate_tuple_back
  • iterate_tuple_id_back

But on "_back" functions I have redefinition error. Why?

10
  • 2
    Playing with defines will make your code very messy, specially generating functions like this. What's wrong with actually writing them? Commented Aug 15, 2014 at 0:25
  • @danikaze You mean writing them twice? Commented Aug 15, 2014 at 0:27
  • 1
    Yeah, I mean writing the actual functions you want to have defined. What's the point on calling twice to the same file to define functions in that way? In the end you will have the same amount of code defined, and it's much more readable if all the functions are written and not defined with that kind of hacks Commented Aug 15, 2014 at 0:29
  • 1
    yeah I supposed that too :P and then when you write them you don't write them with the same inside lol. What I'm trying to say is sometimes we just obfuscate in making something automatically when it's better to use the manual way. Commented Aug 15, 2014 at 0:41
  • 2
    @Leushenko I prefer writing readable and maintainable code instead of automatic one --depending on the case-- Commented Aug 15, 2014 at 0:46

2 Answers 2

1

iterate_tuple_fname##_back is nothing else than iterate_tuple_fname_back. To have iterate_tuple_fname replaced by its macro replacement list, you'll need a helper macro:

#define CONCAT(a, b) a ## b
#define iterate_tuple_fname_back CONCAT(iterate_tuple_fname, _back)

UPDATE: Sorry, have forgotten all about C after several years of C# programming.

It actually needs double run through helper macros:

#define CONCAT1(a, b) a ## b
#define CONCAT(a, b) CONCAT1(a, b)
#define iterate_tuple_fname_back CONCAT(iterate_tuple_fname, _back)
Sign up to request clarification or add additional context in comments.

1 Comment

@tower120, then you'd better post the actual error message you're getting. You also might try running your code through the preprocessor (gcc -E or cl.exe -E).
1

Apparently you misunderstand how the ## operator works.

  • If the preprocessing token adjacent to the ## operator is a parameter of the current macro, then this parameter is recursively analyzed for further replacement first, and the result of that replacement substituted into the result.

  • If the preprocessing token adjacent to the ## operator is not a parameter of the current macro, then recursive analysis and replacement of that token does not take place. The token is simply concatenated with the other token.

Later, once all parameters are substituted and all concatenations are joined, the entire result is rescanned again for further replacements. But then it is already be too late for your example.

In your case you defined this macro

#define iterate_tuple_fname_back iterate_tuple_fname##_back

Since iterate_tuple_fname is not a parameter of this macro, no early replacement occurs for iterate_tuple_fname. The whole thing is immediately concatenated into iterate_tuple_fname_back and only after that it is rescanned. But rescan finds nothing to replace there, so iterate_tuple_fname_back is the final result.

If you want the preprocessor to replace the left-hand side of the ## operator (which was your intent apparently), you absolutely have to use a macro parameter on the left-hand side, as in

#define ITF_back(prefix) prefix##_back

and then you can use this macro as

ITF_back(iterate_tuple_fname)

Now the rescan and recursive replacement inside iterate_tuple_fname will occur early, before the concatenation with the _back part. I.e. it will work as you wanted it to.

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.