Can I substitute __func__ into an identifier name

2020-03-27 07:58发布

问题:

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?

回答1:

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__.



回答2:

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.



回答3:

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.



回答4:

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


标签: c macros