I'm trying to translate my console log with gettext, but I get the follow error:
program.c: In function ‘program_take_screenshot’:
program.c:55:14: error: expected ‘)’ before ‘dcgettext’
#define _(x) gettext(x)
^
program_logger.h:117:49: note: in definition of macro ‘PROGRAM_ERR’
fprintf(LOG_FILE, "Program [ERROR] :: " __VA_ARGS__); \
^
program.c:173:17: note: in expansion of macro ‘_’
PROGRAM_ERR(_("Cannot take screenshot. GPU rendering is used and read_viewport is not supported.\n"));
^
what I do wrong?
definition in program_logger.h:
#define PROGRAM_LOG(...) do { \
if (PROGRAM_LOG_VERBOSE) \
{ \
fprintf(LOG_FILE, "Program: " __VA_ARGS__); \
fflush(LOG_FILE); \
} \
} while (0)
definition of PROGRAM_ERR:
#define PROGRAM_ERR(...) do { \
fprintf(LOG_FILE, "PROGRAM [ERROR] :: " __VA_ARGS__); \
fflush(LOG_FILE); \
} while (0)
Although one of the other answers explains what's going on, it doesn't give you an appropriate means of solving the problem.
What you had:
#define PROGRAM_ERR(...) do { \
fprintf(LOG_FILE, "PROGRAM [ERROR] :: " __VA_ARGS__); \
fflush(LOG_FILE); \
} while (0)
would allow, for example, using it like PROGRAM_ERR("some error: %s", "error message"). Yet as you've found, PROGRAM_ERR(_("some error: %s"), "error message") fails.
The cause is, as explained already, indeed that this expands to
do { fprintf(LOG_FILE, "PROGRAM [ERROR] :: " _("some error: %s"), "error message"); fflush(LOG_FILE); } while(0)
and string concatenation only works for string literals.
In my opinion, the simplest way to make this work, is
#define PROGRAM_ERR(...) do { \
fputs("PROGRAM [ERROR] :: ", LOG_FILE); \
fprintf(LOG_FILE, __VA_ARGS__); \
fflush(LOG_FILE); \
} while (0)
By separating the two strings, you don't need any compile-time string concatenation, which is simply not possible if the strings are not known at compile-time.
Try changing the macro to put ## before __VA_ARGS__. (##__VA_ARGS__) That instructs the preprocessor to place a comma there, but only if there is an argument.
See the gcc documentation here for more details.
Related
I'm working on a university project and I made a macro wrapper of printf which can color the text, print the file, function and line of the instruction with a string error based on errno.
#define PRINT_WITH_COLOR(color, title, message, errno_code) printf(color "[" title "] " message " %s::%s:%d [%s]\n" RESET_COLOR_CONSOLE, __VA_ARGS__, __FILE__, __func__, __LINE__, strerror(errno_code));
This initially was divided in multiple printf but due to multithreading, the problem I'm facing is that when I have no argument to pass the comma remains there and the program doesn't compile.
For that reason I used the ## to remove commas around my variadic parameter:
#define PRINT_WITH_COLOR(color, title, message, errno_code) printf(color "[" title "] " message " %s::%s:%d [%s]\n" RESET_COLOR_CONSOLE, ## __VA_ARGS__, __FILE__, __func__, __LINE__, strerror(errno_code));
I thought it was working because I didn't receive any error on my VS Code but the gcc compiler gives me this error pointing on the right comma next to the __VA_ARGS__ , <----:
expected expression before ‘,’ token
Edit
Here is an example usage:
I use it indirectly by calling this macro
#define PRINT_WARNING(err_code, message, ...) PRINT_WITH_COLOR(YELLOW_COLOR, "Warning", message, __VA_ARGS__)
And in my code I use it like that
PRINT_WARNING(EINVAL, "File %s cannot be written!", pathname);
The output is a yellow message in console [Warning] File foo cannot be written! filepath::func:line [errno msg]
It is actually the macro expansion of PRINT_WARNING that eventually results in the problem, and you should use ## there too. I think you also wanted to pass the err_code as well:
#define PRINT_WARNING(err_code, message, ...) \
PRINT_WITH_COLOR(YELLOW_COLOR, "Warning", message, err_code, ##__VA_ARGS__)
And the PRINT_WITH_COLOR macro should also end in , ...)
#define PRINT_WITH_COLOR(color, title, message, errno_code, ...) \
printf(color "[" title "] " message " %s::%s:%d [%s]\n" RESET_COLOR_CONSOLE, \
##__VA_ARGS__, __FILE__, __func__, __LINE__, strerror(errno_code));
this is the actual macro:
#ifdef DEBUG
#define debug(funcname, format, ...) \
printf(BOLD UNDERLINED REVERSE \
"DEBUG IN " __FILE__ \
" LINE " __LINE__ ":" \
RESET UNDERLINED REVERSE \
"In " funcname \
RESET REVERSE format RESET, ##__VA_ARGS__)
#else
#define debug(funcname, format, ...)
#endif
Where all the constant used are well defined string constants.
I call it with something like:
char message[] = "Hello StackOverflow !\n";
debug("main()", "Message: %s\n", message);
But I get the message
error: expected ‘)’ before numeric constant
debug("main()", "Message: ", message); poiting at the closing parenthese.
It is weird because I first tested the macro, and now that the project has advanced with the team it doesn't work...
That's because
" LINE " __LINE__ ":"
expands to the syntactically invalid
" LINE " 42 ":"
since __LINE__ is an integer, not a string literal that can be concatenated.
I got next debug macro, which works fine:
#ifndef NDEBUG
#define errorLog(fmt, ...) fprintf(stderr, "[ERROR %s: %d] " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif
Except if i try next line (which produce expected a ')' error):
const char* someMessage = "Message";
errorLog(someMessage);
But this one produce no errors:
errorLog("Message");
Right now i solve this like:
const char* someMessage = "Message";
errorLog("%s", someMessage);
How to change macro to work with single const char* param as well?
const char* someMessage = "Message";
errorLog(someMessage); //fprintf(stderr, someMessage)
As written, your errorLog requires a string literal for the first (fmt) argument, as it tries to use string concatenation, which only works with string literals. If you want a macro that can take any char *, not just a string literal, you have to use it directly, rather than pasting. You could use something like:
#define errorLog(...) \
(fprintf(stderr, "[ERROR %s: %d] ", __FUNCTION__, __LINE__), \
fprintf(stderr, __VA_ARGS__), \
fprintf(stderr, "\n"))
This will work for any char *, but will not have the same return value, if you care about that. This also has the advantage that it doesn't depend on the gcc , ## __VA_ARGS__ extension which may not work on other compilers.
If you want this to work properly in a multithreaded program, you might need:
#define errorLog(...) \
(flockfile(stderr), \
fprintf(stderr, "[ERROR %s: %d] ", __FUNCTION__, __LINE__), \
fprintf(stderr, __VA_ARGS__), \
fprintf(stderr, "\n"), \
funlockfile(stderr))
instead
For cleaner error handling I use a macro (it uses C99 and GCC extensions); the behavior is like standard assert:
#define A(cond, msg, ...) ({ \
if (!(cond)) { \
if (msg) \
say(msg, ##__VA_ARGS__); \
else \
say("Error at file %s, function %s, line %u: %s", \
__FILE__, __func__, __LINE__, #cond); \
A_RETURN(); \
} \
})
where say is a formatted output. And use it like that:
#undef A_RETURN
#define A_RETURN() ({ fclose(f); free(p); return false; })
A(foo() != FOO_ERROR, 0);
A(bar() != BAR_ERROR, "bar failed");
When I don't have a specific error message, I have to write A(cond, 0). But I want just write A(cond) in this case. How to modify my A macro for this behavior? I.e. I need a way to check if msg argument isn't passed to the macro.
From the help of suggested question I came to the point that you can modify your macro like this.
#define A() .... //your macro
#define A_CALC_ARG_IMPL(_1,N,...) N
#define A_CALC_ARG(...) A_CALC_ARG_IMPL(__VA_ARGS__,0)
#define A_NEW(...) A(cond, A_CALC_ARG(__VA_RGS__))
so your new A_NEW macro call will be expanded to A(cond, 0) if you don't pass msg.
Variadic macro is explained nicely at this blog.
I'm trying to make a custom printf that prints the file / line no , along with the error message , depending on the current print level set. I've defined a macro for the same. Given below is the code for the preprocessor:
#define DIE (s) \
printf(s); \
exit(0); \
#define my_print(level,s) \
if(level <= gPrintLevel) \
{ \
char *buffer = (char *)malloc(strlen(s)-1); \
if (NULL != buffer) \
{ \
sprintf(buffer,s); \
printf("[%s][%d]:%s\n",__FUNCTION__,__LINE__,buffer); \
if (level == fatal) \
{\
DIE(s);\
}\
} \
} \
I'm calling the above pre-processor like this from inside a function:
myPrint(2,"Unexpected error encountered\n");
But, I'm getting the below compile errors when I try to compile:
41: error: ‘s’ was not declared in this scope
Please help, what am I doing wrong ? Also, its appreciated if someone can tell me if there's a more elegant way of having customized print statements as above. Thanks in advance.
Personally, I would simply assume or mandate that the user provide a literal format string. In that case, you can concatenate strings:
#define MYPRINT(fmt, ...) \
printf("Function: %s. Line: %d. " fmt "\n", \
__FUNCTION__, __LINE__, ## __VA_ARGS__);
Usage:
MYPRINT("The flargle %d has unexpected grobule %f", f->q, f->r);
This approach also lets you take advantage of the compiler's ability to analyze the format string statically and warn you about mismatching arguments.
(The code uses a GCC extension involving ## to elide the final comma in case the argument list is empty.)
OK thanks for all the help guys, the variadic macros solution works fine. This is the new defn of the macro now:
#define DIE(fmt) \
do { \
printf(fmt); \
exit(0); \
} while(0); \
#define my_print(x,fmt,...) \
if (x < gPrintLevel) \
{ \
printf("[%s][%u]:" fmt "\n",__FUNCTION__,__LINE__,##__VA_ARGS__); \
if (fatal == x) \
{\
DIE(fmt) \
}\
} \