I have the following macro function in vanilla C:
#define GLOG(format_string, ...) { \
const char *file = strrchr(__FILE__, '/'); \
char format[256] = "%s:%s!%d\t"; \
strncat(format, format_string, 248); \
strcat(format, "\n"); \
printf(format, __FUNCTION__, file ? file : __FILE__, __LINE__, ##__VA_ARGS__); \
}
which lets me print a debug message containing the current function, file and line number, e.g.
GLOG("count=%d", count);
might print
do_count:counter.c!123 count=456
How can I modify the function to print all local variables if caller omits format_string? e.g.
GLOG();
might print
do_count:counter.c!123 count=456, message="Hello world", array=[7, 8] structure={ptr=0xACE0FBA5E, coord={x=9, y=0}}
If that's not possible, how can I modify it to print just the current function, file and line number? e.g.
do_count:counter.c!123
As is, this returns an error:
error: expected expression before ‘,’ token
as the strncat line is simply
strncat(format, , 248);
First, inspecting all the local variables at runtime by the process itself seems impossible because C doesn't have any means for reflection.
Second, you would be much better off if you wrote the logging macro like that:
#include <stdio.h>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define GLOGF(fmt, ...) \
printf("%s:%s " fmt "\n", __func__, __FILE__ "!" TOSTRING(__LINE__), ##__VA_ARGS__)
int main (void) {
/* main:test.c!xx count=5 */
GLOGF("count=%d", 5);
/* main:test.c!xx */
GLOGF();
return 0;
}
It is simpler and doesn't incur any additional runtime overhead since the string is concatenated at compile-time.
Also note that I have used __func__ instead of __FUNCTION__, because the latter is non-standard.
I found this link in this answer. It might help you with the first part of the question.
The second, how to get all local variables, is much harder, if not impossible. The reason is that the code, when compiled, doesn't actually have variables, it just have offsets into a memory area (the stack.) It might be possible that your compiler have internal functions that can be used to inspect the stack, but then you only have possible values not the names of the variables. The only solution I see it to use special pre-processor macros to declare local variables, and then a list of structures to represent them for introspection, which will be a lot of both runtime and memory overhead.
As others here have mentioned, C does not have reflection features, and therefore you are not going to be capable of capturing the local variables in a macro call. That being said, if you want something to conditionally happen with a macro depending on if there are or are not any arguments to the macro invocation (i.e., your "non-null" and "null" arguments), then you can do something like the following:
#include <string.h>
#define NULL_IDENT ""
#define IDENT(ident_name) #ident_name
#define MACRO(ident_name) \
if (strcmp(NULL_IDENT, IDENT(ident_name)) == 0) { \
/* add code for a null argument passed to the macro */ } \
else { \
/* add code for a non-null argument passed to the macro */ }
Based on Blagovest Buyukliev's answer, I've come up with the following solution for part 2:
#define GLOG(fmt, ...) do { const char *fn = strrchr(__FILE__, '/'); \
printf("%s:%s!%d\t"fmt"\n",__func__,fn?++fn:__FILE__,__LINE__,##__VA_ARGS__);\
} while(0)
using the preprocessor's string concatenation to simply concatenate a null string if the parameter is omitted.
Additionally, I added the do {...} while(0) to swallow the trailing semicolon so that the following if...else works:
if (...)
GLOG();
else
/* do something else */
(idea from http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html ).
Related
I would like to define a macro that would generate program text for me AND also set some non-string macro value. I know that including #define in another #define is not going to work so I'm trying to find a different way.
A simple example:
#include <stdio.h>
#define START_SYNTHETIC int SYNTHETIC_FUNCTION() {
#define END_SYNTHETIC return 0;}
#define SYNTHETIC_FUNCTION my_function
START_SYNTHETIC
printf("Hello from %s", "SYNTHETIC_FUNCTION");
END_SYNTHETIC
int main() {
my_function();
}
This code kinda works, it produces the following output:
Hello from SYNTHETIC_FUNCTION
There are two problems with it:
function name is not expanded and I just have "SYNTHETIC_FUNCTION" in the output. This is currently not critical but might be needed later on.
I dislike having three lines to start my synthetic function. The empty line inserted by autoformatter is especially irritating. Can I reduce this to just a single macro invocation?
Is there a way to define a macro AND output some code in a single statement?
No, in C macros can't define other macros.
function name is not expanded and I just have "SYNTHETIC_FUNCTION" in the output.
Sure it doesn't - it's inside a string literal. Macro replacement is not done inside a string literal.
Can I reduce this to just a single macro invocation?
I do not understand the point at all of this code. Just use __func__.
int my_function(void) {
printf("Hello from %s\n", __func__);
return 0;
}
or pass the name as a macro parameter:
#define SYNTHETIC(name) \
int name(void) { \
printf("Hello from %s\n", #name); \
printf("but really, just use __func__ anyway...: %s\n", __func__); \
return 0; \
}
SYNTHETIC(my_function)
Sometimes I have to send the result of an assert over canbus, sometimes its local.
I use C only, Embitz compiler using GCC, STM32F407 or STM32F103.
My present assert is:
.h file:
extern char *astrbuf;
#define assert(left,operator,right)\
if(!((left) operator (right))) \
{asprintf(&astrbuf,"\nAssert error %s %d %ld %ld\n",__FILE__, __LINE__,\
(u32)(left),(u32)(right));\
asserted();\
}
.c file:
void asserted(void)
{ dprint("%s",astrbuf);
followed by the display code or canbus code.
Example:
assert(millis,<,maxtime);
This works very well, but will be better if the operator can be indicated.
I simply do not see how to display or send the operator, which can be ==, <, or >.
Why not use the standard assert interface and include the whole expression?
#define assert(EXPR) \
if (!(EXPR)) \
{asprintf(&astrbuf, "\nAssert error %s %d %s\n",__FILE__, __LINE__, #EXPR); \
asserted(); \
}
... using the # macro stringification operator.
By the way, why is half of your code in the macro and the other half in the asserted function? Why not do it all in one place?
#define assert(EXPR) \
if (!(EXPR)) \
{ \
asserted(__FILE__, __LINE__, #EXPR); \
}
with
void asserted(const char *file, int line, const char *expr) {
char *astrbuf;
asprintf(&astrbuf, "%s: %d: assertion failed: %s\n", file, line, expr);
dprint("%s", astrbuf);
...
}
Now you don't need a global variable anymore.
There's another potential issue. If you use your macro like this:
if (foo())
assert(x > 42);
else
bar();
... the else bar(); part will attach to the if statement hidden in assert, not the outer if. To fix this, you can wrap the whole thing in a do while loop:
#define assert(EXPR) \
do { \
if (!(EXPR)) { \
asserted(__FILE__, __LINE__, #EXPR); \
} \
} while (0)
Or alternatively make sure the whole macro expands to a single expression:
#define assert(EXPR) \
((void)((EXPR) || (asserted(__FILE__, __LINE__, #EXPR), 0)))
Of course you could also put the conditional logic in the function:
#define assert(EXPR) asserted(!!(EXPR), __FILE__, __LINE__, #expr)
void asserted(int cond, const char *file, int line, const char *expr) {
if (cond) {
return;
}
...
}
You can use the stringizing operator # to convert the macro parameter operator to a string #operator:
extern char *astrbuf;
#define assert(left,operator,right)\
if(!((left) operator (right))) \
{asprintf(&astrbuf,"\nAssert error %s %d %ld %s %ld\n",__FILE__, __LINE__,\
(u32)(left), #operator, (u32)(right));\
asserted();\
}
Perhaps you could try a slightly different approach to achieve the same goal.
Instead of passing (left, operator, right) into the macro, try passing a single boolean condition. You can use the condition inside of your actual assert function and also stringify it using macros. This way you can still report the whole condition to your debug module (canbus).
This will also work for more complicated expressions like ((a-b)< 0)
#define assert( condition ) custom_assert( condition , STRINGIFY_CONSTANT( condition ), __FILE__, __LINE__)
The stringify macro is in its own header file and was derived based on this link. https://gcc.gnu.org/onlinedocs/gcc-3.4.3/cpp/Stringification.html
#define STRINGIFY_CONSTANT(a) STRINGIFY_CONSTANT_DO_NOT_USE(a)
#define STRINGIFY_CONSTANT_DO_NOT_USE(a) #a
Obviously, don't use STRINGIFY_CONSTANT_DO_NOT_USE
void custom_assert( int condition , const char * condition_string, const char * file_name, int line_number)
{
if (!condition)
{
dprint("Assert Failed:'%s' File:'%s' Line:'%d'",condition_string, file_name, line_number);
}
}
I would avoid putting anything more than a single function call into your assert #define as that can be hard to debug and it will also increase the size of your code. I recommend putting any logic into the function.
I called my assert custom_assert. I also have many #defines to put the debug output to different channels like usb, rs232, a on screen display, etc. In release mode the asserts just reboot the embedded device, which is acceptable in my application.
Assert is a macro, the way I understand it, it is always inline.
The code for the machine has lots of asserts to prevent damage, therefore one needs to keep the code as fast as possible, ie. inline under normal circumstances.
When anything goes wrong, the function asserted is used, speed is no more a problem, safety is. The function asserted switches off motors, etc, and reports over canbus or local display. No way I want to do all that in a macro.
That is why part of the code is in a macro, part in a function.
Please correct me if my understanding is wrong.
Not having a global variable is a definite plus, and I have added the while (0), as in other macros.
My goal is to print the filenames and not relative path to the filename. I'm experimenting with it using the macro TRACE().
Since it's all in the same file, I'm simulating the filename as an input to TRACE(). So in real life, you could say the inputs are replaced with __FILE__.
Code:
#include <stdio.h>
#include <string.h>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define __FILENAME__(x) TOSTRING(strrchr(x, '\\'))
#define TRACE(s, ...) \
{ \
if (strrchr(s, '\\')) { \
static const char str[] = __FILENAME__(s) "\n\r"; \
printf(str, ##__VA_ARGS__); \
} else { \
static const char str[] = s "\n\r"; \
printf(str, ##__VA_ARGS__); \
} \
}
int main() {
TRACE("file.c");
TRACE("parent\\file.c");
return 0;
}
Output:
file.c
strrchr("parent\\file.c", '\\')
So if it's local file, it's printed as file.c, which is great. This means the ifcase in the macro is working :). But when it's a file in another folder, I fail to "stringify" the computation strrchr(s, '\\'). Why?
Furthermore, I don't see an issue with the computation in the define, since everything is defined at compile time!! (That's why the if case is working, right?)
If I remove the TOSTRING() from __FILENAME__ I get loads of errors instead. Because it fails to concatenate the output of __FILENAME__ with str[]
Is there a way to solve this?
Preliminary observations
Note that in C (as opposed to C++), you can't initialize a static const char str[] array with the result of a function call. If the strrchr() found a backslash, you probably want to print the name from one after the backslash. And the stringification isn't going to stringify the result of invoking strrchr().
Also note that you should not create function or variable names that start with an underscore, in general. C11 §7.1.3 Reserved identifiers says (in part):
All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
See also What does double underscore (__const) mean in C?
Since the first argument to your TRACE macro is already a string, there's not much benefit to applying the stringification — unless you want the double quotes to appear when the name is printed.
Simple adaptation
To get more or less the result you want, you would need to accept that there'll be run-time overhead invoking strrchr() each time you pass the trace (or a more elaborate scheme for initialization), along the lines of:
#define TRACE(s, ...) \
do { \
const char *basename = strrchr(s, '\\'); \
if (basename == 0) \
basename = s; \
else \
basename++; \
printf(basename, ## __VA_ARGS__); \
} while (0)
The do { … } while (0) idiom is standard; it allows you to write:
if (something)
TRACE("hocuspocus.c: test passed\n");
else
TRACE("abracadabra.c: test failed\n");
If you use the braces-only notation in the question, the semicolon after the first TRACE makes the else into a syntax error. See also C #define macro for debug printing and Why use apparently meaningles do { … } while (0) and if … else statements in macros? and do { … } while (0) — what is it good for?
The ## __VA_ARGS__ trick is fine as long as you know that it is a GCC (and Clang because it is compatible with GCC) extension, and not a part of standard C.
It also isn't entirely clear how you plan to use the variable arguments. It looks as though you'd be able to do:
TRACE("some\\kibbitzer.c: value %d is out of the range [%d..%d]\n",
value, MIN_RANGE, MAX_RANGE);
where the file name is embedded in the format string. Maybe you have in mind:
TRACE(__FILE__ ": value %d is out of the range [%d..%d]\n",
value, MIN_RANGE, MAX_RANGE);
That can work; __FILE__ is a string literal, unlike __func__ which is a predefined identifier (static const char __func__[] = "…function name…";).
Finally (for now), consider whether trace output should go to standard output or to standard error. It is easily arguable it should go to standard error; it (probably) isn't part of the regular output of the program.
I recommend looking at the 'debug macro' question and answer — but I am biassed since I wrote the top-scoring answer.
Reducing runtime overhead
You can reduce the runtime overhead to a single call to strrchr() per file name, as long as you aren't messing with automatic variables etc. You'll be OK if you're using string literals.
#define TRACE(s, ...) \
do { \
static const char *basename = 0;
if (basename == 0) \
{
if ((basename = strrchr(s, '\\')) == 0) \
basename = s; \
else \
basename++; \
} \
printf(basename, ## __VA_ARGS__); \
} while (0)
This initializes the basename to null; on the first pass through the code, basename is set to the correct position in the string; thereafter, there is no further call to strrchr().
Warning: the code shown has not been compiled.
I think there is some issue with the understanding of how macros and functions work.
Macros are not "executed", they are just simple text substitution. Yes, that happens in the compile time (actually pre compiling), but just the substitution.
Macros won't execute and code or call any functions (like strrchr) while compiling.
In your code you have -
#define __FILENAME__(x) TOSTRING(strrchr(x, '\\'))
Whenever __FILENAME__(foo) is used, it is replaced with "strrchr(foo, '\\')". I am sure this is not what you want.
Personally, I don't see any reason for using macros here. Just make it into a normal function. The compiler will optimize it for you.
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));
I'm trying to write a debug print macro that will print the function name with the option of including format/varargs to print the parameters as well.
I've set up my modules so that each has it's on print color by adding a style variable to the individual modules and using it in my print macro.
The working print macro is as follows
//myprint.h
...
#define STYLE_UNDERLINE "\033[4m"
#define STYLE_NORMAL "\033[0m"
#define STYLE_BLUE "\033[0;34m"
... // more colo(u)rs here
#define PRINTF(fmt, ...) printf("%s" fmt STYLE_NORMAL, style, ##__VA_ARGS__)
...
Usage:
//myfile.c
...
static char * style = STYLE_BLUE;
void myFunc(int i) {
PRINTF("String with no params\n");
PRINTF("i value %d\n", i);
}
I'd like to do something similar with a PRINT_FN macro that would be used as follows
//myfile.c
...
void myFunc(int i) {
PRINT_FN(); // just print the function name
// equivalent to
PRINTF("%s%s()", STYLE_UNDERLINE, __func__);
PRINT_FN("%d", i) // print the function name and parameter
// equivalent to
PRINTF("%s%s(%d)", STYLE_UNDERLINE, __func__, i);
}
I can figure out a macro that almost accomplishes this, the problem being that it requires you to minimally send an empty format string.
#define PRINT_FN(fmt, ...) printf("%s" STYLE_UNDERLINE "%s(" fmt ")" STYLE_NORMAL, \
style, __func__, ##__VA_ARGS__)
Is there a way I can also make the fmt parameter optional?
Don't try to cram everything into one printf. Separate the adornments and the actual output:
#define PRINT_FN(...) \
do { \
printf("%s%s: ", STYLE_UNDERLINE, __func__); \
printf("" __VA_ARGS__); \
printf("%s\n", STYLE_NORMAL); \
} while (0)
Concatenating an empty string leads to an empty string if the format is empty or to the original format otherwise. gcc's -Wall setting warns about an empty format string, however.
The do ... while shold be compiled away and serves to make the macro behave as one statement. Maybe overkill in yor case, but still.