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.
Related
I have a macro called PRINT(...) that I use in my code, which gets a variable number of arguments and acts like printf (gets a format and arguments). It's defined like this:
#define PRINT(...) PRINT(__VA_ARGS__)
Now I want to modify it so it will have an optional argument, say that its name is number and it will add a numeric prefix to the printing. For example:
PRINT("%s", "hi") -> will print hi
PRINT(1, "%s", "hi") -> will print 1: hi
How can I change the PRINT macro to support this?
Important to say, that I don't want to change any existing call to this macro from my code (in the example, if I have a call to PRINT("%s", "hi") - it needs to remain the same after the change).
Also, I can't create new macro for this purpose- must use the existing PRINT macro for this purpose (but off course I can change it's arguemnts definition).
Any idea how can I do this?
Edit: I saw this post about variadic macro- but It's different from what I'm asking here since the argument number needs to be a recognized variable, which will be treated in the implementation of PRINT as -1 if the call to PRINT doesn't contain the number argument (-1 will be an indicator for printing no number) and otherwise it will print the number prefix.
As of C11, you can use the _Generic keyword. This allows you to check the type of any value or variable. According to this document, _Generic has behaviour that varies between compilers. This answer provides a simple solution, though, using the comma operator.
#define PRINT(fst, ...) \
( \
_Generic((0, fst), char *: 1, default: 0) ? \
PRINTNL(fst, __VA_ARGS__) : \
PRINTL(fst, __VA_ARGS__) \
)
Where PRINTNL prints without the number and PRINTL prints with the number.
Rest of the code:
#define PRINTNL(...) printf(__VA_ARGS__)
#define PRINTL (n, ...) ({ \
printf("%d: ", n); \
printf(__VA_ARGS__); \
})
Since you'd know by the time of writing whether the first argument is a number prefix or not, make a macro by another name for prefixing with the number. Here I assume that PRINT(...) expands to printf(__VA_ARGS__):
#define PRINT(...) printf(__VA_ARGS__)
So define a macro NPRINT that calls printf twice, once to output the prefix with number and once with the format:
#define NPRINT(number, fmt, ...) (printf("%d: ", number), printf(fmt, __VA_ARGS__))
Usage
#include <stdio.h>
int main(void) {
NPRINT(1, "%s\n", "hi");
}
Of course this doesn't work if the call to printf was supposed to be atomic - now if the format string was always a literal string, then you could use string concatenation:
#define NPRINT(number, fmt, ...) (printf("%d " fmt, number, __VA_ARGS__))
If it can be a variable and only one call to PRINT is allowed, the only portable way that I could see is to make a function that builds the format.
With the latest edit that without the number argument, -1: should be prefixed, this would simply become:
#define PRINT(...) NPRINT(-1, __VA_ARGS__)
Please have a look at the ##__VA_ARGS__ macro. Also check the code below written for a log function.
In the header file
/**
* ##__VA_ARGS__ allows us to make varadic arguments optional
* https://gcc.gnu.org/onlinedocs/gcc/Variadic-Macros.html
* also check __VA_OPT__ (C++20)
*/
#define APP_LOG(message, ...) \
do { \
APP_LOGX( __FILE__, __LINE__, ("\e[1;34m[INFO]: \e[0m" message), ##__VA_ARGS__); /** BLUE */ \
} \
while(0)
#define APP_ERROR(message, ...) \
do { \
APP_LOGX( __FILE__, __LINE__, ("\e[1;31m[FATAL]: \e[0m" message), ##__VA_ARGS__); /** RED */ \
} \
while(0)
In the implementation
/** #include <libgen.h> */
void APP_LOGX(const char * file, int num, const char* message, ...)
{
va_list ap;
int length;
char * tfilename = NULL;
tfilename = strdup(file);
length = strlen(message);
if(length>0){
va_start(ap, message);
vprintf(message, ap);
printf(" | File: %s Line %d ", basename(tfilename), num);
va_end(ap);
/* add newline if nessasary */
if(message[length -1] != '\n'){
printf("\n");
}
}
free(tfilename);
}
Application
APP_LOG("app display init")
or
APP_LOG("Value of x acceleration %.2f", g);
APP_ERROR("Something bad happened!")
In C, we often have to run such code
if (! somefun(x, y, z)) {
perror("somefun")
}
Is it possible to create a macro which, used as follows:
#define chkerr ...
chkerr(somefun(x, y, z));
would compile to the above?
I already know I can use __VA_ARGS__ macro, but this would require me to call it like
chkerr(somefun, x, y, z)
Short variant (you spotted already):
#define chkErr(FUNCTION, ...) \
if(!FUNCTION(__VA_ARGS__)) \
{ \
perror(#FUNCTION); \
}
Be aware that this can impose big problems in nested if/else or similar constructs:
if(x)
chkErr(f, 10, 12) //;
//^ semicolon forgotten!
else
chkErr(f, 12, 10);
would compile to code equivalent to the following:
if(x)
{
if(!f(10, 12))
perror("f");
else if(!f, 12, 10))
perror("f");
}
Quite obviously not what was intended with the if/else written with the macros... So you really should prefer to let it look like a real function (requiring a semicolon):
#define chkErr(FUNCTION, ...) \
do \
{ \
if(!FUNCTION(__VA_ARGS__)) \
{ \
perror(#FUNCTION); \
} \
} \
while(0)
You would call it like this:
chkErr(someFunction, 10, 12);
In case of error, output would be:
someFunction: <error text>
However, this hides the fact that a function actually gets called, making it more difficult to understand for "outsiders". Same output, not hiding the function call, but requiring one additional comma in between function and arguments (compared to a normal function call):
#define chkErr(FUNCTION, ARGUMENTS) \
do \
{ \
if(!FUNCTION ARGUMENTS) \
{ \
perror(#FUNCTION); \
} \
} \
while(0)
chkErr(someFunction,(12, 10));
// ^ (!)
Another variant with the charm of retaining the function call would print out this entire function call:
#define chkErr(FUNCTION_CALL) \
do \
{ \
if(!FUNCTION_CALL) \
{ \
perror(#FUNCTION_CALL); \
} \
} \
while(0)
chkErr(someFunction(10, 12));
In case of error, output would be:
someFunction(10, 12): <error text>
Addendum: If you really want exactly the output as shown in the question and still have the function call retained (without comma in between), you are a little in trouble. Actually, it is possible, but it requires some extra work:
Problem is how the preprocessor operates on macro arguments: Each argument is a token. It can easily combine tokens, but cannot split them.
Leaving out any commas results in the macro accepting one single token, just as in my second variant. Sure, you can stringify it, as I did, but you get the function arguments with. This is a string literal, and as the pre-processor cannot modify string literals, you have to operate on them at runtime.
Next problem then is, though, string literals are unmodifiable. So you need to modify a copy!
The following variant would do all this work for you:
#define chkErr(FUNCTION_CALL) \
do \
{ \
if(!FUNCTION_CALL) \
{ \
char function_name[] = #FUNCTION_CALL; \
char* function_name_end = strchr(function_name, '('); \
if(function_name_end) \
*function_name_end = 0; \
perror(function_name); \
} \
} \
while(0)
Well, decide you if it is worth the effort...
By the way - whitespace between function name and opening parenthesis is not eliminated. If you want to be perfect:
unsigned char* end = (unsigned char*) function_name;
while(*end && *end != '(' && !isspace(*end))
++end;
*end = 0;
Or, much nicer (thanks chqrlie for the hint):
function_name[strcspn(function_name, "( \t")] = 0;
Anything else I can think of would require an additional pre-processing step:
#define CAT(X, Y) CAT_(X, Y)
#define CAT_(X, Y) X ## Y
#define chkErr(FUNCTION_CALL) \
do \
{ \
if(!FUNCTION_CALL) \
{ \
perror(CAT(CHK_ERR_TEXT_, __LINE__)); \
} \
} \
while 0
chkErr(function(10, 12));
Ah, huh, this would result in code like this:
if(!function(10, 12))
{
perror(CHK_ERR_TEXT_42);
}
And now, where to get these macros from? Well, the pre-processing, remember? Possibly a perl or python script, e. g. generating an additional header file you'd have to include. You would have to make sure this pre-processing is done every time before the compiler's pre-processor runs.
Well, all not impossible to solve, but I'll leave this to the masochists among us...
C11 6.4.2.2 Predefined identifiers
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.
You can used it this way:
#define chkErr(exp) do { if (!(exp)) perror(__func__); } while (0)
chkerr(somefun(x, y, z));
Unfortunately, this would produce an error message with the name of the calling function, not somefun. Here is a simple variant that should work and even produce more informative error messages:
#define chkErr(exp) do { if (!(exp)) perror(#exp); } while (0)
chkerr(somefun(x, y, z));
In case somefun(x, y, z) returns a non zero value, the error message will contain the string "somefun(x, y, z)".
You can combine both techniques to give both the offending call and the location:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#define chkErr(exp) \
do { if (!(exp)) \
fprintf(stderr, "%s:%d: in function %s, %s failed: %s\n",\
__FILE__, __LINE__, __func__, #exp, strerror(errno)); \
} while (0)
chkerr(somefun(x, y, z));
This assumes somefun() returns 0 or NULL in case of error and set errno accordingly. Note however that most system calls return non zero in case of error.
You can use the original call format:
chkerr(somefun(x, y, z));
With a macro and a helper function:
#define chkerr(fcall) \
if (!fcall) { \
perror(extract_fname(#fcall)); \
}
const char *extract_fname(const char *fcall);
The extract_fname function would get text and return everything until the open parenthesis.
Yes it is possible with an ugly, unsafe variadic macro:
#define chkerr(func, ...) \
if(!func(__VA_ARGS__)) \
{ \
perror(#func); \
}
...
chkerr(somefunc, 1, 2, 3);
But it is a very bad idea.
Call for sanity:
If there was just the original code with the plain if statement, the reader would think "Here they call a function and do some basic error control. Okay, basic stuff. Moving on...". But after the changes, anyone who reads the code will instead freeze and think "WTF is this???".
You can never write a macro that is clearer than the if statement - which makes the if statement superior to the macro.
Some rules to follow:
Function-like macros are dangerous and unreadable. They should only be used as the very last resort.
Avoid inventing your own secret macro language with function-like macros. C programmers who read your code know C. They don't know your secret macro language.
"To avoid typing" is often a poor rationale for program design decisions. Avoiding code repetition is a good rationale, but taking it to the extremes will affect code readability. If you avoid code repetition and make the code more readable at the same time, it is a good thing. If you do it but the code turns less readable, it is hard to justify.
It's not possible to extract just the function name. The C processor sees the literals you pass as single tokens, which can't be manipulated. Your only options are to print the function with arguments like Aconcague suggests or pass the name as a separate parameter:
#define chkErr(FUNCTION_NAME, FUNCTION_CALL) \
if(!FUNCTION_CALL) \
{ \
perror(#FUNCTION_NAME); \
}
chkErr(someFunction, someFunction(10, 12));
Sometimes, in a C code I borrowed from a linux driver, I want to change some macros into a function that I can use in my environment. But this previous macro can take 3 or 4 arguments.
For example, if I want to substite
SMSC_TRACE(pdata, probe, "Driver Parameters:"); // 3 arguments
into
printf("Driver Parameters:");
and substitute
SMSC_TRACE(pdata, probe, "LAN base: 0x%08lX", (unsigned long)pdata->ioaddr); // 4 arguments
into
printf("LAN base: 0x%08lX", (unsigned long)pdata->ioaddr);
How do I do that? I tried
#define SMSC_TRACE((a), (b), (c)) printf((c))
#define SMSC_TRACE((a), (b), (c), (d)) printf((c), (d))
but it doesn't seem to work. Only the last one seems to take effect.
EDIT: this seems it maybe.
#define SMSC_TRACE(pdata, nlevel, fmt, args...) printf(fmt "\n", ##args)
You can do it with a variadic macro, which takes a variable number of arguments:
#define SMSC_TRACE(a,b,...) printf(__VA_ARGS__)
If you want this macro to execute multiple statements, then you need a do/while(0).
For example:
#define SMSC_TRACE(a,b,...) \
do \
{ \
printf("%c\n",a); \
printf("%d\n",b); \
printf(__VA_ARGS__); \
} \
while (0)
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) \
}\
} \
I have macro like this:
#define error_exit(format, ...) \
error_at_line(EXIT_FAILURE, 0, __FILE__, __LINE__, format, ##__VA_ARGS__)
that I use to as a general fatal error function. Unfortunately, error_at_line doesn't have the noreturn gcc attribute because if you specify 0 as the first argument it does return. This causes problems, specifically, I get uninitialized variable warnings because gcc can't figure out that error_exit will never return.
For example:
int x;
switch(...) {
case VALID:
x = 1;
break;
default:
error_exit(...);
}
return x;
gives me warning. So, how can I go about apply noreturn to a macro or even specific function invocation?
Assuming GCC ā„ 4.5.0,
#define error_exit(format, ...) \
do { \
error_at_line(EXIT_FAILURE, 0, __FILE__, __LINE__, format, ##__VA_ARGS__); \
__builtin_unreachable(); \
} while (0)
The only sensible way is to create a new function that calls error_at_line that is marked noreturn. A macro cannot be marked noreturn, nor can a function that sometimes returns.
Instead of a #define, use an inline function to wrap the function, and mark it noreturn.