2

I'd like to write a C macro which takes this:

int foo() {
  MY_MACRO
}

and expands it to this:

int foo() {
  _macro_var_foo++;
}

I've found that I can't use __func__, because that doesn't actually get expanded in the macro; it's treated by the preprocessor like a variable.

Is there some way to get this to work?

Justin L.
  • 3,957
  • 3
  • 31
  • 29

4 Answers4

4

The preprocessor doesn't know about functions, just source files and line numbers. At that stage it's not performing syntactical analysis, just textual analysis and substitutions. That's why __func__ is a magical variable instead of a magical macro like __FILE__ and __LINE__.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • That's very sensible. But my understanding is that GCC used to what I want. I'm disappointed there's no way to get this feature anymore. – Justin L. Oct 12 '09 at 02:59
3

In the C99 standard, __func__ is given a special new category of 'predefined identifier' (in section 6.4.2.2 Predefined Identifiers):

The identifier __func__ shall be implicitly declared by the translator as if, immediately following the opening brace of each function definition, the declaration

    static const char __func__[] = "function-name";

appeared, where function-name is the name of the lexically-enclosing function

This means that it is out of the scope of the C preprocessor, which is not aware of function boundaries or function names. Further, it would expand to a string, which makes it inappropriate for embedding into a variable name.


The GCC (4.4.1) manual says in section 5.43 (Function Names as Strings):

These identifiers [meaning __func__, __FUNCTION__ and __PRETTY_FUNCTION__] are not preprocessor macros. In GCC 3.3 and earlier, in C only, __FUNCTION__ and __PRETTY_FUNCTION__ were treated as string literals; they could be used to initialize char arrays, and they could be concatenated with other string literals. GCC 3.4 and later treat them as variables, like __func__. In C++, __FUNCTION__ and __PRETTY_FUNCTION__ have always been variables.

If there was a way to get the function name into a preprocessor cleanly, then it is probable that the documentation here would have cross-referenced it, if it did not define it.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

You can do this using token concatenation.

#define MY_MACRO(baz) _macro_var_##baz++;

#define FUNC_WRAPPER(bar)\
int bar()\
{\
    MY_MACRO(bar)\
}

FUNC_WRAPPER(foo)

The output from gcc -E:

int foo(){ _macro_var_foo++;}

Version dealing with argument lists using variadic macros and x macros:

#define MY_MACRO(baz) _macro_var_##baz++;

#define FUNC_DEF(ret_type,bar,...)\
ret_type bar(__VA_ARGS__)\
{\
    MY_MACRO(bar)\
    FUNC_CONTENTS\
}

#define FUNC_CONTENTS\
    printf("Do some stuff\n", s1, s2);
FUNC_DEF(int, foo, char *s1, char *s2)
#undef FUNC_CONTENT
DMC
  • 231
  • 2
  • 4
  • Unfortunately, you can't concatenate `__func__` in a macro, because the preprocessor treats it like a variable. – Justin L. Oct 12 '09 at 03:20
  • I'm suggesting that you scrap usage of __func__ and instead pass the name of your function in to FUNC_WRAPPER(). Same result. – DMC Oct 12 '09 at 03:22
  • Oh sure, passing the function name to the macro is an option. But I was hoping for something sexier. :) – Justin L. Oct 12 '09 at 03:34
  • @jonathan-leffler: dealing with argument lists is horrible as you can see! This solution is orthogonal however mismatches between the variadic arg list and the use of those args in the x macro is caught at compilation, not at the preprocessing stage. Not a huge problem I think. – DMC Oct 12 '09 at 04:15
1

Technically, the answer to your question is "yes", there is "some way". But I think you already knew that, and it's true that you cannot deal with this at the macro preprocessor level.

Sure, there is always a way, you just might need a really long tape on that Turing Machine.

I think you already know this, but for the record you can get the overall result you want with:

#define MY_MACRO f_dictionary(__func__, ADDONE);

So now, you just need to implement f_dictionary and an ADDONE op for it.

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329