1

I have a logging macro and a function, and I would like for them to have the same name, so that when I miss the header with the macro, the program would still build (via C implicit function declaration).

I've tried:

/* Declare function. */
void logmsg(const char *fmt, ...) __attribute__((format(printf, 1, 2)));

/* Declare macro (with the same name). */
#define logmsg(fmt, ...) \
        logmsg(fmt, ##__VA_ARGS__)

However this fails with a compilation error:

In file included from util.c:53:
../lib/util.h:296:13: error: expected identifier or ‘(’ before ‘do’
  296 |             do { if (1) (logmsg(fmt, ##__VA_ARGS__)); } while (0)
      |             ^~
util.c:248:6: note: in expansion of macro ‘logmsg’
  248 | void logmsg(const char *fmt, ...)
      |      ^~~~~~
../lib/util.h:296:59: error: expected identifier or ‘(’ before ‘while’
  296 |             do { if (1) (logmsg(fmt, ##__VA_ARGS__)); } while (0)
      |                                                           ^~~~~
util.c:248:6: note: in expansion of macro ‘logmsg’
  248 | void logmsg(const char *fmt, ...)

How can I accomplish my goal?

EDIT:

I've solved the issue via the indirect self-reference of macro identifier like the following:

void logmsg(const char *fmt, ...) __attribute__((format(printf, 1, 2)));

#define log_impl(specarg, fmt, ...) \
            logmsg(fmt,##__VA_ARGS__)

#define logmsg(fmt, ...) \
            log_impl(msg,fmt,##__VA_ARGS__)

The msg arg to log_impl() is rather not needed, but I've stashed the code and cannot test it to be sure.

psprint
  • 349
  • 1
  • 10
  • 1
    I'm not sure what this has to do with implicit declaration, which in any case has been illegal since C99. – Nate Eldredge Jan 12 '21 at 23:46
  • 4
    I think your original intent is misguided. If you forget to include a header, the best result is for it to cause an error, so you can fix it by adding the `#include`. – Barmar Jan 12 '21 at 23:46
  • Call the function differently and link one object without macro include but with a functon the name of the macro, that calls the differently named function. Not really nice. – Joop Eggen Jan 12 '21 at 23:46
  • [Can't reproduce.](https://tio.run/##fU9Na8MwDL37V4jmYoc0Zbt2DAqD3jfYqWA0fySCxA6O0h3GfnvmZs3WXaaDQE9PT@@ZbWPMXFAw3WQdPIxsKdbto/gDYWoyNu9KeHKmw@TAT8EwxVBDuRPnSBa62PRjI00MI4NpMUHpe66grmsFWiNzoreJndZS@ph6ZDkkCuwruKvgXim1F4uS@FfpQ0CuM@qO8haH/TqPjIklDhVksrrC3x/kco6D@iG7YOUyfwpxk6pHkyLId@IWuHUwYu8g5KaWnIV1noJbo/6aOi26l7pdFYXWrwd9eD6@aK2EmLOX/IICyDXHlb5p6RQ2FzvzFw) – jxh Jan 12 '21 at 23:47
  • Can you post a [mcve]? I'm confused as to what exactly is in your header, what's in your source file, and where the error occurs. – Nate Eldredge Jan 12 '21 at 23:48
  • @Barmar: I've often do temporary debugging runs across multiple files, adding `#include`s is tedious in such scenario… – psprint Jan 13 '21 at 00:08
  • Also note that calling a function with ellipsis (`, ...`) in the argument list without a prototype in scope is undefined behaviour. C11 [§6.5.2.2 Function calls](http://port70.net/~nsz/c/c11/n1570.html#6.5.2.2p6): _If the function is defined with a type that includes a prototype, and either the prototype ends with an ellipsis (`, ...`) or the types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined._. You need to avoid undefined behaviour. This applies in C90 as well as C99, C11, C18. – Jonathan Leffler Jan 13 '21 at 03:01

2 Answers2

3

You need to guard against the logmsg macro expanding in your declaration(s) of the logmsg function and in its definition.

What should work regardless of your ordering of the macro definition and your real C code referring to the logmsg function is always using parentheses around references to the logmsg function:

void (logmsg)(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void (logmsg)(const char *fmt, ...)
{
//...
}
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
1

The macro substitution is happening in the source file at the point the function named logmsg is defined. Since this macro is only valid at the point when the function is called, you end up with a syntax error. You need to undefine the macro at that point:

#undef logmsg
void logmsg(const char *fmt, ...)
{
    ...
dbush
  • 205,898
  • 23
  • 218
  • 273