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.