Undefined variable error in C macros (for customized prints) - c

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) \
}\
} \

Related

C logging with variadic macros

I'm trying to write an overhead-free logging macro in C.
My first idea is:
#define debug_print(...) \
{ \
printf(_LOG_FMT, _LOG_ARGS); \
printf(__VA_ARGS__); \
printf("\n"); \
}
But this has the problem that I have to call printf three times (overhead).
My second idea is:
#define _LOGFUNCTION(LEVEL, message, ...) \
printf(_LOG_FMT message "\n", _LOG_ARGS, __VA_ARGS__)
But now I can't pass it a simple string to log. It'll complain about zero arguments in VA_ARGS.
Is there a way to fix both of these problems?
Thanks a ton for your help!
Found the answer form the comment above!
#define BAR_HELPER(fmt, ...) printf(fmt "\n%s", __VA_ARGS__)
#define BAR(...) BAR_HELPER(__VA_ARGS__, "")
https://stackoverflow.com/a/8673872/5531233
Thanks again Some programmer dude!

How to use gettext with __VA_ARGS__ in c

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.

Checking if an argument is passed in variadic macros in C

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.

C function to a macro

I need to write a macro instead of a function in C
The function is as follows :
void FSTATUS(int stat,char msg[])
{
if(stat != 0)
{
EMH_ask_error_text(stat, &msg);
printf("Error : \"%d\",\"%s\"\n",stat,msg);
}
else
printf("\n -------- %s -------- \n",msg);
}
as there are very less examples available how to use if statement in macros , I am stuck with this part where I am not able to figure out how to convert this into a macro. Can anyone please help me out with the above code.
Solution :
I used an inline function instead of a macro
#define FSTATUS(stat, msg) do \
{ \
if((stat) != 0) \
{ \
EMH_ask_error_text(stat, &(msg)); \
printf("Error : \"%d\",\"%s\"\n",stat,msg); \
} \
else \
printf("\n -------- %s -------- \n",msg); \
} while (0)
Note the use of do { ... } while (0) to ensure that this works correctly between if/else.
Note also the use of additional parentheses in some places to avoid problems when stat or msg is an expression.
And of course be very aware of all the pitfalls of macros - you really should not use this type of function macro unless you have a very good reason to. Ideally you should use an inline function if performance really is critical, otherwise just stick with a normal function.
Proper formatting makes a huge difference, I believe. That's why I always align \'s.
#define FSTATUS(stat, msg) \
do \
{ \
if ((stat) != 0) \
{ \
EMH_ask_error_text((stat), &(msg)); \
printf("Error : \"%d\",\"%s\"\n", (stat), (msg)); \
} \
else \
{ \
printf("\n -------- %s -------- \n", (msg)); \
} \
} \
while (0)
Important: Make sure there's no white space behind the \ at the end of the lines. White space 'breaks' the line-break.
Of course you could also do:
#define FSTATUS(s, m) ((s) ? (EMH_ask_error_text((s), &(m)), printf("Error : \"%d\",\"%s\"\n", (s), (m))) : printf("\n -------- %s -------- \n", (m)))
Here the comma operator is used as separator between the two statements in the if-block.
#define FSTATUS(stat,msg) \
do { \
if(stat != 0) \
{ \
EMH_ask_error_text(stat, &msg); \
printf("Error : \"%d\",\"%s\"\n",stat,msg); \
} \ \
else \
printf("\n -------- %s -------- \n",msg);\
}while(0)
Only need to do is changing the function type to macro. If you wonder why need to add do {.. } while(0) ,you can reference this :http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html#Swallowing-the-Semicolon

Using and returning output in C macro

I'm trying to instrument some code to catch and print error messages. Currently I'm using a macro somethng like this:
#define my_function(x) \
switch(function(x)) { \
case ERROR: \
fprintf(stderr, "Error!\n"); \
break; \
}
Normally, I never capture the function output and this works fine. But I've found a couple cases where I also need the return value of function(). I tried something like the following, but this produces a syntax error.
#define my_function(x) \
do { \
int __err = function(x); \
switch(__err) { \
case ERROR: \
fprintf(stderr, "Error!\n"); \
break; \
} \
__err; \
} while(0)
I could declare a global variable to hold the return value of the function, but that looks ugly and my program is multithreaded, so that's likely to cause problems. I'm hoping there's a better solution out there.
GCC has a feature called statement expressions
So if define macro like
#define FOO(A) ({int retval; retval = do_something(A); retval;})
then you will be able to use it like
foo = FOO(bar);
This is relatively complicated code, there is not much reason to have it in a macro. Make it inline (C99) or static (C89) or both if you really want to place it in a header file. With any reasonable compiler this then should result in the same efficiency as a macro.
A very late reply. But none the less. I agree inline functions are better but MACROs do offer some pretty printing fun you can't get with inline functions. I agree with #qrdl that you can indeed use statement expressions had you restructured your statements a bit. Here is how it would work with a macro -
#define my_function(x, y) ({ \
int __err = 0; \
do { \
__err = function(x, y); \
switch(__err) { \
case ERROR: \
fprintf(stderr, "Error!\n"); \
break; \
} \
} while(0); \
__err; \
})
Sorry, this is an edit...
I think you just need the curly braces. No need for the do..while keywords
Make sure that the backslashes are the last characters on each line (no space after).
If you need to get the err value out of the macro, you can just add a parameter
Like so:
#define my_function(x, out) \
{ \
int __err = function(x); \
switch(__err) { \
case ERROR: \
fprintf(stderr, "Error!\n"); \
break; \
} \
__err; \
(*(out)) = _err; \
}
To preserve the pass-by-reference C paradigm, you should call my_function this way:
int output_err;
my_function(num, &output_err);
This way, later, if you decide to make my_function a real function, you don't need to change the call references.
Btw, qrdl's "Statement Expressions" is also a good way to do it.
there is no need to declare variable if your function is returning something then you can directly get that value. For example:
#define FOO(A) do_something(A)
Here do_something returns some integer. Then you can easily use it like:
int a = FOO(a);

Resources