tags:

views:

444

answers:

4

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?

+3  A: 

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
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.
+1  A: 

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
Unfortunately, you can't concatenate `__func__` in a macro, because the preprocessor treats it like a variable.
Justin L.
I'm suggesting that you scrap usage of __func__ and instead pass the name of your function in to FUNC_WRAPPER(). Same result.
DMC
Do you plan to show how to deal with argument lists?
Jonathan Leffler
Oh sure, passing the function name to the macro is an option. But I was hoping for something sexier. :)
Justin L.
@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
+1  A: 

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
lol, yes. But at that point, I might as well just type the function's name into the macro. :)
Justin L.
+1  A: 

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