Reputation: 14281
I have a macro to do a version of default arguments:
#define Log_getMacro4(_1, _2, _3, _4, NAME, ...) NAME
#define Log_logWarning4(...) Log_log__("warning", __VA_ARGS__)
#define Log_logWarning3(...) Log_log__("warning", __VA_ARGS__, __LINE__)
#define Log_logWarning2(...) Log_log__("warning", __VA_ARGS__, __FILE__, __LINE__)
#define Log_logWarning1(...) Log_log__("warning", __VA_ARGS__, __PRETTY_FUNCTION__, __FILE__, __LINE__)
#define Log_logWarning(...) Log_getMacro4(__VA_ARGS__, Log_logWarning4, Log_logWarning3, Log_logWarning2, Log_logWarning1)(__VA_ARGS__)
The problem is that I now want to provide a variant on that function which frees the first argument to Log_logWarning after:
#define Log_logWarning_free(str, ...) Log_logWarning(str, __VA_ARGS__); if (str) free(str);
The problem is that this cannot be used with the return value of a function. For example:
char *foo(){
char *ret = (char*)malloc(30*sizeof(char));
strcpy(ret, "Hello World");
return ret;
}
void bar(){
Log_logWarning_free(foo());
}
Therefore, I was wondering if there is a way to create a local variable first to which I will assign the first argument of the macro and then use that variable in the test and subsequent free.
Upvotes: 1
Views: 240
Reputation: 12140
I would use an inline function instead, if at all possible.
If you have to use a macro, use a do { ... } while (0)
construct:
#define Log_logWarning_free(str, ...) \
do { \
char * logtmp_ = str; \
Log_logWarning(logtmp_, __VA_ARGS__); \
if (logtmp_) free(logtmp_); \
} while (0)
The do-while-0 trick allows you to have a code block, while it prevents accidentally attaching the block to an another flow control construct incorrectly.
This full test program compiles with 4.7.2:
#include <stdlib.h>
#define Log_logWarning_free(str, ...) \
do { \
char * logtmp_ = str; \
Log_logWarning(logtmp_, __VA_ARGS__); \
if (logtmp_) free(logtmp_); \
} while (0)
void Log_logWarning(char* fmt, ...);
char * get_log_str(void);
int main()
{
Log_logWarning_free(get_log_str(), 1, 2, 3);
return 0;
}
Upvotes: 2
Reputation: 154047
The problem is knowing the type of the variable (except in C++11). For the rest, you can use the usual trick for scoping:
#define X(y) do { auto CONCAT(_log_tmp_,__LINE__) = (y); ... } while(false);
In C and in C++ pre-C++11, you'll probably have to pass the type of the variable in as an argument to the macro.
Upvotes: 1
Reputation: 25199
Firstly, wrap your functions in do { } while(0)
so you can add a semicolon to your usage of the functions and avoid weird errors.
Secondly, yes, you can use a local variable. See http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html for examples.
An simple example would be
#define swap(a,b) do {int _c=b; b=a; a=_c;} while(0)
That can then be safely invoked as:
int x = 5;
int y = 7;
swap(x, y);
See also: Can a C macro contain temporary variables?
Upvotes: 1