Optional Parameters with C++ Macros
Here's one way to do it. It uses the list of arguments twice, first to form the name of the helper macro, and then to pass the arguments to that helper macro. It uses a standard trick to count the number of arguments to a macro.
enum
{
plain = 0,
bold = 1,
italic = 2
};
void PrintString(const char* message, int size, int style)
{
}
#define PRINT_STRING_1_ARGS(message) PrintString(message, 0, 0)
#define PRINT_STRING_2_ARGS(message, size) PrintString(message, size, 0)
#define PRINT_STRING_3_ARGS(message, size, style) PrintString(message, size, style)
#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
#define PRINT_STRING_MACRO_CHOOSER(...) \
GET_4TH_ARG(__VA_ARGS__, PRINT_STRING_3_ARGS, \
PRINT_STRING_2_ARGS, PRINT_STRING_1_ARGS, )
#define PRINT_STRING(...) PRINT_STRING_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
int main(int argc, char * const argv[])
{
PRINT_STRING("Hello, World!");
PRINT_STRING("Hello, World!", 18);
PRINT_STRING("Hello, World!", 18, bold);
return 0;
}
This makes it easier for the caller of the macro, but not the writer.
c Macro with multiple optional arguments
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.
Does C support optional null parameters?
C does not support optional parameters. Nor does it support function overloading which can often be used to similar effect.
Optional Function Parameters C
It seems like it would be simpler to do:
size_t strlchr(const char *str, const char ch, const int strln)
{
//function code if strlen == -1 (no parameter)
//function code if strlen != -1 (parameter given)
}
#define strlchr_macro(STR, CH, STRLN, ...) strlchr(STR, CH, STRLN)
#define strlchr(...) strlchr_macro(__VA_ARGS__, -1, -1)
this makes both the ch
and strln
arguments optional, defaulting to -1 if not provided. It also allows you to provide more than 3 arguments (the extra will be ignored), which may be undesirable but probably not a show-stopper.
Is it possible to get macro passed as optional argument to variadic function using va_arg
A first possibility is to just do
cp_syslog(id, "SYSLOG_CONN_DISALLOW");
Execution :
pi@raspberrypi:/tmp $ ./a.out
String is SYSLOG_CONN_DISALLOWMacro is %d: Disallowing new connections. Reason: %s.
pi@raspberrypi:/tmp $
(a newline is missed in the first printf
or do cp_syslog(id, "SYSLOG_CONN_DISALLOW\n")
)
But this is artificial and even the definition of cp_syslog
is artificial because that one knows the macro is SYSLOG_CONN_DISALLOW
being in its definition.
If you want to give to 'something else' both the name of a macro and its 'value' just use an intermediate macro like :
#define NAME_VALUE(x) #x, x
The expansion of NAME_VALUE(SYSLOG_CONN_DISALLOW)
is "SYSLOG_CONN_DISALLOW", "%d: Disallowing new connections. Reason: %s.\n", 3201008
That time cp_syslog
does not have to know it applies on SYSLOG_CONN_DISALLOW
:
#include <stdio.h>
#include <stdarg.h>
#define CONN_DISALLOW 3201008
#define SYSLOG_CONN_DISALLOW \
"%d: Disallowing new connections. Reason: %s.\n", CONN_DISALLOW
#define NAME_VALUE(x) #x, x /* ADDED */
void cp_syslog(int syslogid, ...);
void cp_syslog(int syslogid, ...)
{
char *syslog_disallow;
va_list ap;
va_start(ap, syslogid);
syslog_disallow = va_arg(ap, char *);
printf("String is %s\n", syslog_disallow); /* \n ADDED */
printf("Macro is %s", va_arg(ap, char *)); /* MODIFIED */
va_end(ap);
}
int main()
{
int id = 2;
cp_syslog(id, NAME_VALUE(SYSLOG_CONN_DISALLOW)); /* MODIFIED */
return 0;
}
Compilation and executon :
pi@raspberrypi:/tmp $ gcc pp.c
pi@raspberrypi:/tmp $ ./a.out
String is SYSLOG_CONN_DISALLOW
Macro is %d: Disallowing new connections. Reason: %s.
pi@raspberrypi:/tmp $
C/C++ macros with parameters
##
is the pasting operator. It ensures that the compiler thinks that the left side and the right side are just one token. If you write GET_INSTANCE_PROC_ADDR(foo, bar)
, then demo->fp##entrypoint
becomes demo->fpbar
.
#
gets the contents of the macro argument as a string. If you write GET_INSTANCE_PROC_ADDR(foo, bar)
, then #entrypoint
is "bar"
.
In C and C++, it's legal to put two string literals next to one another and the compiler will concatenate them: "this" "is" "valid"
is the same as "thisisvalid"
.
C++ and MSVC #define directive with optional arguments
That's not how printf()
works.
Your macro expands:
INFODUMP("%d", 42);
To:
std::printf("INFO: %s\n", "%d", 42)
You need:
#define INFODUMP(s, ...) std::printf("INFO: " ## s ## "\n", __VA_ARGS__)
Which will then expand:
INFODUMP("%d", 42);
To:
std::printf("INFO: %d\n", 42)
Related Topics
How to Convert Std::String to Lpcwstr in C++ (Unicode)
Why Does Call-By-Value Example Not Modify Input Parameter
How to Get the Md5 Hash of a File in C++
High Resolution Timer With C++ and Linux
Why Would One Use Nested Classes in C++
Const& , & and && Specifiers For Member Functions in C++
C++: Constructor Initializer For Arrays
Why Should Exceptions Be Used Conservatively
Vector of Vectors to Create Matrix
Initializing a Member Array in Constructor Initializer
How to Assign an Alias to a Function Name in C++
What Is the Worst Real-World Macros/Pre-Processor Abuse You'Ve Ever Come Across
How to Get Available Memory C++/G++
Should I Use Std::Function or a Function Pointer in C++
How to Check If a C++ String Is an Int