Optional Parameters With C++ Macros

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



Leave a reply



Submit