-1

I am trying to create a log function that will take the log type, msg and will add file name, function name, line from where the log function was called. I have created the following test code but getting errors that I don't understand

#include<stdio.h>

#define func(type, msg, ...) func(type, __FILE__, __func__, __LINE__, msg, __VA_ARGS__)

void func(int type, const char *file, const char *function, int line, const 
          char *msg, ...)
{
     printf("%s",msg);
}

main()
{
    func(10,"time");
}

here is the error log:

||=== Build file: "no target" in "no project" (compiler: unknown) ===|
E:\code\C code\A.c|6|error: expected declaration specifiers or '...' before string constant|
E:\code\C code\A.c|3|error: expected declaration specifiers or '...' before '__func__'|
E:\code\C code\A.c|6|note: in expansion of macro 'func'|
E:\code\C code\A.c|6|error: expected declaration specifiers or '...' before numeric constant|
E:\code\C code\A.c|6|warning: type defaults to 'int' in declaration of 'msg' [-Wimplicit-int]|
E:\code\C code\A.c|3|note: in definition of macro 'func'|
E:\code\C code\A.c|12|warning: return type defaults to 'int' [-Wimplicit-int]|
E:\code\C code\A.c||In function 'main':|
E:\code\C code\A.c|3|warning: implicit declaration of function 'func' [-Wimplicit-function- 
declaration]|
E:\code\C code\A.c|15|note: in expansion of macro 'func'|
E:\code\C code\A.c|3|error: expected expression before ')' token|
E:\code\C code\A.c|15|note: in expansion of macro 'func'|
||=== Build failed: 4 error(s), 3 warning(s) (0 minute(s), 0 second(s)) ===|

I have read this question but I can't relate the solutions with my code.

Reshad
  • 220
  • 5
  • 19
  • The function name `func` is replaced with your define. – Alex Lop. Dec 29 '19 at 06:30
  • 1
    `const *msg` -> `const char *msg` – kaylum Dec 29 '19 at 06:31
  • after changing char *func to char *fnc the errors are still there – Reshad Dec 29 '19 at 06:33
  • `FILE` is a type in `` (or, at least, `FILE *` is). That might be throwing things off. You should make it `const char *file` in the function, I suggest (adding `const` and renaming it. Rename `LINE` to lower-case `line` too, for consistency. – Jonathan Leffler Dec 29 '19 at 07:05
  • Suggest replacing `void func(int type, char *FILE, char *fnc, int LINE, const cahr *msg, ...)` with `void (func)(int type, const char *file, const char *function, int line, const char *msg, ...)`. The parentheses around `func` prevent it being treated as an invocation of the macro. I'd use `function` in preference to `fnc`, but YMMV. I'd probably rename `msg` as `fmt` too — it looks like it will probably a format string for one of the `printf()` family of functions (one of the `vprintf()` family, in fact). And I'd probably use a more meaningful name for the function than `func`. – Jonathan Leffler Dec 29 '19 at 07:10
  • changing the definition did reduced the previous errors now it is giving a new error error: expected '=', ',', ';', 'asm' or '__attribute__' at end of input – Reshad Dec 29 '19 at 07:14
  • OK — please add the new definition and new error message to the question so we can help. And do the editing before notifying us via comments that you've changed some things and now get different errors. – Jonathan Leffler Dec 29 '19 at 07:15
  • sorry I did one mistake while changing the code. I am still getting the same errors. I have edited the question for the changes in the code – Reshad Dec 29 '19 at 07:18
  • You've not used `void (func)(...)` when defining the function — those parentheses are CRUCIAL! – Jonathan Leffler Dec 29 '19 at 07:22
  • yes without the parentheses it does not work. can you explain why they are crucial or help with some resource so I can understand this much better. thank you for your help – Reshad Dec 29 '19 at 08:16

1 Answers1

1

Your code might reasonably be:

#include <stdio.h>
#include <stdarg.h>
#include <time.h>

extern void (logger)(int type, const char *file, const char *function, int line, const char *fmt, ...);

#define logger(type, msg, ...) logger(type, __FILE__, __func__, __LINE__, msg, __VA_ARGS__)

void (logger)(int type, const char *file, const char *function, int line, const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    printf("%s:%d:%s() - %d: ", file, line, function, type);
    vprintf(fmt, args);
    va_end(args);
}

int main(void)
{
    logger(10, "time %ld\n", (long)time(0));
}

The extra argument is needed so that the __VA_ARGS__ has something to refer to. See #define macro for debug printing in C for an extensive discussion. The simplest portable fix is probably to change the macro to include the format string as part of the __VA_ARGS__.

#define logger(type, ...) logger(type, __FILE__, __func__, __LINE__, __VA_ARGS__)

With this change, you can use this once more:

int main(void)
{
    logger(10, "time\n");
}

It is probably better to separate the macro name that people will use (logger) from the function name (e.g. logger_loc, with the loc indicating 'location' information). However, a cognizant user can write (logger)(10, "elephants.c", "pachyderm", 31921, "time\n"); if they wish to invoke the function directly. Because logger is not followed immediately by a ( token, it is not an invocation of the function-like macro logger.

There is also a GCC-specific workaround for the 'missing __VA_ARGS__' problem, and C++20 has also worked on the issue and produced a different solution (see Portably detect __VA_OPT__ support?), which I expect is likely to appear in a future C standard (and in C compilers before that hypothetical future C standard).

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • it's not working when I call the logger function without variable length arguments logger(10, "time"); – Reshad Dec 29 '19 at 07:59
  • Which version isn't working? The one I said won't work, or the one which I said will work? Because frankly I will have a hard time believing you if you claim that the version that I said will work with just a simple argument like `"time\n"` after the `type` information (that is, the macro `#define logger(type, ...) logger(type, __FILE__, __func__, __LINE__, __VA_ARGS__)`) actually doesn't work. You'd have to provide proof — you could send me email (see my profile) with your code if need be. Also, read that other question; it goes through what's necessary too. – Jonathan Leffler Dec 29 '19 at 08:04
  • I was trying to implement it on my own after reading your code and I forgot to remove the msg in the macro. your code works fine thank you for the solution. – Reshad Dec 29 '19 at 08:09
  • here is the macro and function definition #define log_msg(type, ...) log_msg(type, __FILE__, __func__, __LINE__, __VA_ARGS__) void (log_msg)(int type, const char *fileName, const char *functionName, int line, const char *fmt, ...); this works fine when I run this in windows but when I put the same code in openwrt( a unix based os for router) it gives the following error error: expected expression before ')' token #define log_msg(type, ...) log_msg(type, __FILE__, __func__, __LINE__, __VA_ARGS__) why is that? – Reshad Dec 29 '19 at 10:58