如何创建定义变量的宏?

时间:2014-01-22 18:45:38

标签: c++ c

我有一个宏来做一个默认参数的版本:

#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__)

问题是我现在想要在该函数上提供一个变体,它在第一个参数之后释放Log_logWarning:

#define Log_logWarning_free(str, ...) Log_logWarning(str, __VA_ARGS__); if (str) free(str);

问题是这不能与函数的返回值一起使用。例如:

char *foo(){
    char *ret = (char*)malloc(30*sizeof(char));
    strcpy(ret, "Hello World");
    return ret;
}

void bar(){
    Log_logWarning_free(foo());
}

因此,我想知道是否有办法首先创建一个局部变量,我将为其分配宏的第一个参数,然后在测试中使用该变量,随后将其释放。

3 个答案:

答案 0 :(得分:2)

如果可能,我会使用内联函数。

如果必须使用宏,请使用do { ... } while (0)构造:

#define Log_logWarning_free(str, ...) \
    do { \ 
        char * logtmp_ = str; \
        Log_logWarning(logtmp_, __VA_ARGS__); \
        if (logtmp_) free(logtmp_); \
    } while (0)

do-while-0 trick允许您拥有代码块,同时防止意外地将块意外地附加到另一个流控制结构。

这个完整的测试程序编译为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;
}

答案 1 :(得分:1)

首先,将您的函数包装在do { } while(0)中,这样您就可以为函数的使用添加分号,避免出现奇怪的错误。

其次,是的,您可以使用局部变量。有关示例,请参阅http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html

一个简单的例子是

#define swap(a,b) do {int _c=b; b=a; a=_c;} while(0)

然后可以安全地调用它:

int x = 5;
int y = 7;
swap(x, y);

另请参阅:Can a C macro contain temporary variables?

答案 2 :(得分:1)

问题在于知道变量的类型(除了 C ++ 11)。对于其他人,您可以使用通常的技巧来确定范围:

#define X(y) do { auto CONCAT(_log_tmp_,__LINE__) = (y); ...  } while(false);

在C和C ++前C ++ 11中,您可能必须传递该类型 变量作为宏的参数。