18

I am using gcc to compile C99 code. I want to write a macro which will return a string containing the function name and line number.

This is what I have:

#define INFO_MSG  __FILE__ ":"__func__"()"

However, when I compile code which attempts to use this string, for example:

char buff[256] = {'\0'}
sprintf(buff, "Something bad happened here: %s, at line: %d", INFO_MSG, __LINE__);
printf("INFO: %s\n", buff);

I get the following error message:

error: expected ‘)’ before ‘__func__’

I have tracked the problem down to the macro. as when I remove __func__ from the macro, the code compiles correctly.

How do I fix the macro, so that I can include the predefined __func__ macro in my string?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Homunculus Reticulli
  • 65,167
  • 81
  • 216
  • 341
  • 1
    Use the the compiler's expander switch to see what is spit out. – leppie Aug 18 '13 at 12:02
  • 1
    I don't believe `__func__` is a macro. Maybe you could put the `INFO_MSG` into the format string instead? `sprintf(buff, "Something bad happened here: %s:%s(), at line: %d", __FILE__, __func__, __LINE__);` – tangrs Aug 18 '13 at 12:19
  • @leppie: can you clarify? - what do you mean by expander?. BTW, I am using gcc. – Homunculus Reticulli Aug 18 '13 at 12:22
  • @tangrs: `__func__` is a predefined macro in **C99** (AFAIK). – Homunculus Reticulli Aug 18 '13 at 12:23
  • `gcc -E` will output the expanded output. – leppie Aug 18 '13 at 12:32
  • 2
    Doesn't seem to be a macro on gcc 4.2.1. `echo "const char* test() { return __func__; }" | gcc -xc -E -std=c99 -` shows `const char* test() { return __func__; }`. Edit: apparently [it isn't a macro](http://stackoverflow.com/a/4384825/268025). – tangrs Aug 18 '13 at 12:33
  • @HomunculusReticulli: No; `__func__` is a predefined identifier. ISO/IEC 9899:2011 6.4.2.2 **Predefined identifiers**: ***Semantics*** _¶1 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._ – Jonathan Leffler Aug 18 '13 at 14:12

4 Answers4

23

Judging from your comments, the objective is to have a macro which combines the file name and function name (and maybe line number) into a single string that can be passed as an argument to functions such as printf() or strcpy() or syslog().

Unfortunately, I don't think that's possible.

The C11 standard says:

ISO/IEC 9899:2011 §6.4.2.2 Predefined identifiers

¶1 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.

Therefore, __func__ is not a macro, unlike __FILE__ or __LINE__.

The related question What's the difference between __PRETTY_FUNCTION__, __FUNCTION__, __func__? covers some alternative names. These are GCC-specific extensions, not standard names. Moreover, the GCC 4.8.1 documentation says:

These identifiers 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.

There are sound reasons why these cannot be preprocessor constructs. The preprocessor does not know what a function is and whether the text it is processing is in the scope of a function, or what the name of the enclosing function is. It is a simple text processor, not a compiler. Clearly, it would be possible to build that much understanding into the preprocessor (solely for the support of this one feature), but it is not required by the standard, and neither should it be required by the standard.

Unfortunately, though, I think it means that attempts to combine __func__ (by any spelling) with __FILE__ and __LINE__ in a single macro to generate a single string literal are doomed.

Clearly, you can generate the file name and line number as a string using the standard two-step macro mechanism:

#define STR(x) #x
#define STRINGIFY(x) STR(x)

#define FILE_LINE __FILE__ ":" STRINGIFY(__LINE__)

You can't get the function name into that as part of a string literal, though.

There are arguments that the file name and line number are sufficient to identify where the problem is; the function name is barely necessary. It is more cosmetic than functional, and slightly helps programmers but not other users.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • ok, I think this will have to do then - atleast, a filename and line number should help in debug messages. – Homunculus Reticulli Aug 18 '13 at 18:24
  • 1
    There is one ghastly alternative that's not thread-safe and that uses runtime copying: `extern const char *file_line_func(const char *file, int line, const char *func);` which is invoked from a macro and formats the information into a static string (hence it is not thread-safe) and returns a pointer to that string. Works OK in the likely usage contexts (error reporting), but modestly expensive. You can improve a bit by passing the result of the FILE_LINE macro as a single argument in place of the `file` and `line` arguments. But it is still ugly. Very ugly. – Jonathan Leffler Aug 18 '13 at 18:39
  • *There are arguments that the file name and line number are sufficient to identify where the problem is* Waaay late here, but merely having the location of the problem does not provide any context. If a logging system has a level, say `TRACE`, where it logs all function calls and returns, including function arguments and return values, logging a problem in such a system at a detailed-enough level will provide the full context of the error and make troubleshooting almost trivial. There's no better way to figure out what's going on then having the process literally tell you. – Andrew Henle Dec 28 '22 at 16:00
4

After a quick experiment I found that you cannot use __func__ with stringification. It would not make much sense if you could as this would mean that the value would be wherever the macro is defined instead of where it is applied.

The nature of __func__, as noted in the comments on the question, is described in this answer.

Stringification is performed at pre-processor time and because of that __func__ is unavailable as it is essentially a function local string that is defined later on the compilation process.

However you can use __func__ in a macro as long as you don't use stringification on it. I think the following performs what you're after:

#include <stdio.h>

#define INFO_MSG "Something bad happened here: %s : %s(), at line: %d", \
                 __FILE__, __func__, __LINE__

int main()
{
    char buff[256] = {'\0'};
    sprintf(buff, INFO_MSG);
    printf("INFO: %s\n", buff);
    return 0;
}

Note that there's no particular reason, in the question as presented, to use a string buffer. The following main function would achieve the same effect without the possibility of buffer overrun:

int main()
{
    printf("INFO: ");
    printf(INFO_MSG);
    printf("\n");
    return 0;
}

Personally, I'd wrap up the whole process in the macro like this:

#include <stdio.h>

#define INFO_MSG(msg) printf("%s: %s : %s(), at line: %d\n", \
                        msg, __FILE__, __func__, __LINE__)

int main()
{
    INFO_MSG("Something bad happened");
    return 0;
}
Community
  • 1
  • 1
Don Cruickshank
  • 5,641
  • 6
  • 48
  • 48
  • You can stringify `__LINE__` with the usual two stage trick: `#define STR(x) #x`, `#define STRINGIFY(x) STR(x)`, and then `STRINGIFY(__LINE__)`. You can't do anything with `__func__` which is a pre-defined identifier (variable), not a constant string. – Jonathan Leffler Aug 18 '13 at 13:52
  • Thanks. I've amended my answer. – Don Cruickshank Aug 18 '13 at 14:07
  • Hmm, this is not ideal. I was using that macro to dynamically generate the function name as a string (with earlier versions of gcc). I will have to rewrite a lot of code just because of this, I'll investigate to see if I can avoid doing that. BTW, its the string I need, as I am not always writing to the stdout (i.e. console), I only used printf for the sake of brevity/clarity. – Homunculus Reticulli Aug 18 '13 at 16:01
3

Remark that, "__func__ is not a function so it cannot be called; in fact, it is a predefined identifier that points to a string that is the name of the function, and is only valid inside the scope of a function." - Jonathan.

The following is what you are looking for:

#define TO_STR_A( A ) #A
#define TO_STR( A ) TO_STR_A( A )
#define INFO_MSG TO_STR( __LINE__ ) ":" __FILE__

char buff[ 256 ] = { 0 };

sprintf( buff, "Something bad happened here, %s in function %s().", INFO_MSG, __func__ );
printf( "INFO: %s\n", buff );

... note that a call to __func__ can be made inside the function itself. See this.

Jacob Pollack
  • 3,703
  • 1
  • 17
  • 39
  • Indeed you need to use `__func__` inside the function itself, but you can pre-process it first. – Don Cruickshank Aug 18 '13 at 13:11
  • `__FILE__` is already a string; it does not need to be stringified. `__func__` is not a function so it cannot be called; in fact, it is a predefined identifier that points to a string that is the name of the function, and is only valid inside the scope of a function. – Jonathan Leffler Aug 18 '13 at 14:06
  • @JonathanLeffler, fixed answer -- thanks for the informative follow-up. – Jacob Pollack Aug 18 '13 at 14:24
1

it is a syntax error. I try to come over with your macro specification but I didnt find a efficient way, so maybe you can try this:

#define INFO_MSG  __FILE__ , __FUNCTION__   

int main()
{
    char buff[256] = {'\0'};
    sprintf(buff, "Something bad happened here: %s : %s(), at line: %d", INFO_MSG, __LINE__);
    printf("INFO: %s\n", buff);
}
Christos Papoulas
  • 2,469
  • 3
  • 27
  • 43