3

I am trying to use a function-like macro to generate an object-like macro name (generically, a symbol). The following will not work because __func__ (C99 6.4.2.2-1) puts quotes around the function name.

#define MAKE_AN_IDENTIFIER(x) __func__##__##x

The desired result of calling MAKE_AN_IDENTIFIER(NULL_POINTER_PASSED) would be MyFunctionName__NULL_POINTER_PASSED. There may be other reasons this would not work (such as __func__ being taken literally and not interpreted, but I could fix that) but my question is what will provide a predefined macro like __func__ except without the quotes? I believe this is not possible within the C99 standard so valid answers could be references to other preprocessors.

Presently I have simply created my own object-like macro and redefined it manually before each function to be the function name. Obviously this is a poor and probably unacceptable practice. I am aware that I could take an existing cpp program or library and modify it to provide this functionality. I am hoping there is either a commonly used cpp replacement which provides this or a preprocessor library (prefer Python) which is designed for extensibility so as to allow me to 'configure' it to create the macro I need.


I wrote the above to try to provide a concise and well defined question but it is certainly the Y referred to by @Ruud. The X is...

I am trying to manage unique values for reporting errors in an embedded system. The values will be passed as a parameter to a(some) particular function(s). I have already written a Python program using pycparser to parse my code and identify all symbols being passed to the function(s) of interest. It generates a .h file of #defines maintaining the values of previously existing entries, commenting out removed entries (to avoid reusing the value and also allow for reintroduction with the same value), assigning new unique numbers for new identifiers, reporting malformed identifiers, and also reporting multiple use of any given identifier. This means that I can simply write:

void MyFunc(int * p)
{
    if (p == NULL)
    {
        myErrorFunc(MYFUNC_NULL_POINTER_PASSED);
        return;
    }

    // do something actually interesting here
}

and the Python program will create the #define MYFUNC_NULL_POINTER_PASSED 7 (or whatever next available number) for me with all the listed considerations. I have also written a set of macros that further simplify the above to:

#define FUNC MYFUNC
void MyFunc(int * p)
{
    RETURN_ASSERT_NOT_NULL(p);

    // do something actually interesting here
}

assuming I provide the #define FUNC. I want to use the function name since that will be constant throughout many changes (as opposed to LINE) and will be much easier for someone to transfer the value from the old generated #define to the new generated #define when the function itself is renamed. Honestly, I think the only reason I am trying to 'solve' this 'issue' is because I have to work in C rather than C++. At work we are writing fairly object oriented C and so there is a lot of NULL pointer checking and IsInitialized checking. I have two line functions that turn into 30 because of all these basic checks (these macros reduce those lines by a factor of five). While I do enjoy the challenge of crazy macro development, I much prefer to avoid them. That said, I dislike repeating myself and hiding the functional code in a pile of error checking even more than I dislike crazy macros.

If you prefer to take a stab at this issue, have at.

8
  • 1
    Unfortunately there is no such way using the standard C preprocessor, not without passing in the actual name of the function as an argument to the macro. You also have to remember here that __func__ is not actually part of the preprocessor, it should be treated like a real variable (a character array to be precise). Commented Apr 4, 2014 at 12:19
  • @JoachimPileborg I understand that this is not possible within the C99 preprocessor and am looking for other possibilities. I have edited the question to try to make that more clear. Commented Apr 4, 2014 at 12:22
  • @altendky - I think the only way is to write your own pre-processor Commented Apr 4, 2014 at 12:23
  • It will probably not be possible with other preprocessors either, unless they are specifically tailored to parse and understand the source file, which few are. Commented Apr 4, 2014 at 12:23
  • 1
    @Ruud I try to ask direct and concise questions generally, but I have added the X you requested along with the detailed backstory. I am at a loss as to why they decided to quote __func__. If they had not then we could easily #define QUOTE(x) #x, #define EXPAND(x) x and #define FUNC() QUOTE(EXPAND(__func__)) and end up with both unquoted and quoted function name options. Commented Apr 4, 2014 at 23:44

3 Answers 3

1

__FUNCTION__ used to compile to a string literal (I think in gcc 2.96), but it hasn't for many years. Now instead we have __func__, which compiles to a string array, and __FUNCTION__ is a deprecated alias for it. (The change was a bit painful.)

But in neither case was it possible to use this predefined macro to generate a valid C identifier (i.e. "remove the quotes").

But could you instead use the line number rather than function name as part of your identifier?

If so, the following would work. As an example, compiling the following 5-line source file:

 #define CONCAT_TOKENS4(a,b,c,d)      a##b##c##d
 #define EXPAND_THEN_CONCAT4(a,b,c,d) CONCAT_TOKENS4(a,b,c,d)
 #define MAKE_AN_IDENTIFIER(x)        EXPAND_THEN_CONCAT4(line_,__LINE__,__,x)

 static int MAKE_AN_IDENTIFIER(NULL_POINTER_PASSED);

will generate the warning:

foo.c:5: warning: 'line_5__NULL_POINTER_PASSED' defined but not used

Sign up to request clarification or add additional context in comments.

2 Comments

I am trying to maintain consistency of the actual values through the development and having line numbers changing all the time would make that much more difficult. Thanks for taking the time to give this a shot.
See my detailed comment against the question itself, but yes, I can use the line number as you suggest. It simply requires two separate files to be generated. Two files when manually maintaining would be terrible, but as I would be generating them it is just fine. Thanks for helping me get to my solution that bypasses the question.
1

As pointed out by others, there is no macro that returns the (unquoted) function name (mainly because the C preprocessor has insufficient syntactic knowledge to recognize functions). You would have to explicitly define such a macro yourself, as you already did yourself:

#define FUNC MYFUNC

To avoid having to do this manually, you could write your own preprocessor to add the macro definition automatically. A similar question is this: How to automatically insert pragmas in your program

If your source code has a consistent coding style (particularly indentation), then a simple line-based filter (sed, awk, perl) might do. In its most naive form: every function starts with a line that does not start with a hash or whitespace, and ends with a closing parenthesis or a comma. With awk:

{
    print $0;
}

/^[^# \t].*[,\)][ \t]*$/ {
    sub(/\(.*$/, "");
    sub(/^.*[ \t]/, "");
    print "#define FUNC " toupper($0);
}

For a more robust solution, you need a compiler framework like ROSE.

1 Comment

I think it is finally settling in. It is not the preprocessor which expands func to "MyFunc" but rather the preprocessor simply ignores func and lets the compiler itself treat it as an actual C symbol... ROSE certainly looks to be a good thing for me to be aware of on this topic. Thanks for pointing it out. Ditto on the pragma insertion question.
0

Gnu-C has a __FUNCTION__ macro, but sadly even that cannot be used in the way you are asking.

2 Comments

This should be a comment at most.
I appreciate the response but 'there is something that does not do what you want' does not answer a question which is specifically not constrained to cpp.

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.