Reputation: 27
I have a messaging function that takes a variable amount of arguments because it supports string formatting in the same way printf does. My plan was to then define message code and messages with a single #define
and be able to call this function by passing it a single argument for something that is tightly related.
Here is the message macro:
#define MSG(a, b, ...) message(__FILE__, __LINE__, a, b, __VA_ARGS__);
And here is an example of the message code and string define:
#define MSG_INIT 0000,"%s INITIALIZED SUCCESSFULLY"
The issue is occurring when I try to make a call in the form of:
MSG(MSG_INIT);
My IDE is giving me an error along the lines of:
'Expands to message("file.c", 1, 0000, "INITIALIZED SUCCESSFULLY",);
where the last ',' is causing the issue.
I was expecting to see:
'Expands to message("file.c", 1, 0000, "INITIALIZED SUCCESSFULLY");
If I change the call to:
MSG(MSG_INIT,NULL);
All is good but I'd rather not pass the NULL because the point of the MSG_INIT
define in the first place was to pass less parameters. There are messages that make use of the __VA_ARGS__
(Example: #define MSG_CONNECT 0001,"CONNECTION TO [%s] ESTABLISHED"
with matching call MSG(MSG_CONEST, server_ip);
) so getting rid of that is not an option. I am just looking for the best way to fix this problem and I'm aware a lot of people suggest staying away from the preprocessor but this was the best solution I thought of.
Upvotes: 0
Views: 1161
Reputation: 881103
I'm aware a lot of people suggest staying away from the preprocessor ...
I wonder why that is. Could it possibly be for the same reason you had to ask this question? :-)
Honestly, the pre-processor should be limited pretty much to including header files and doing conditional compilation. Anything else that it used to be used for, such as:
#define RC_OK 0
#define RC_NOMEM 1
#define HALF_OF(x) x / 2
is far better done with enumerations or functions.
The days of function-like macros should be put behind us, especially since modern compilers can quite easily out-optimise most hand-crafted code, and without subtle errors creeping in such as with that HALF_OF
macro above (do not use it, I specifically made it buggy to illustrate a point).
It's really just a text substitution thing, one which understands the lexical elements, but not the full grammar of C. The fact that you have to perform what I call "macro gymnastics" to get it to do anything other than simple stuff is reason enough to steer clear. Use functions for this, it'll make your life a lot easier.
And apologies for not solving your specific issue, I just think any solution using the pre-processor is going to be half-baked at best. But there's plenty of precedent on SO for answering the question "How do I X?" with "Don't X, it's better to Y." Think of writing an accounting package in assembler, an operating system in object-oriented COBOL, or anything in Pascal :-)
But, if you really wanted to stick to macros against my advice, you could try starting with something like:
#include <stdio.h>
#define MSG(fmtStr, ...) printf("%s:%d> " fmtStr, __FILE__, __LINE__, __VA_ARGS__)
#define MSG_INIT "Initialised %s\n"
#define MSG_TERM "Terminated %s with values %d and %d\n"
int main(void) {
MSG("%f\n", 42.3);
MSG(MSG_INIT, "something");
MSG(MSG_TERM, "something else", 7, 42);
}
I think that's portable, and it allow you to put the heavy lifting into MSG
and using a separate format string and parameters for the rest of the stuff:
testprog.c:8> 42.300000
testprog.c:9> Initialised something
testprog.c:10> Terminated something else with values 7 and 42
Upvotes: 1