Xeo*_*Xeo 34
如果您想要实际的文本替换,那就是您使用宏的地方.看看Boost.Preprocessor,这是在C++ 03中模拟可变参数模板的好方法,而不会重复太多.
换句话说,如果您想操纵程序代码本身,请使用宏.
另一个有用的应用是assert,未定义时定义为无操作NDEBUG(通常是释放模式编译).
这将我们带到下一点,这是第一点的特殊化:具有不同编译模式的不同代码,或者在不同编译器之间.如果您需要交叉编译器支持,则无法在没有宏的情况下逃脱.一般来看看Boost,它一直需要宏,因为它必须支持各种编译器的各种缺陷.
另一个重要的一点是,当您需要呼叫站点信息而不想让您的代码用户出错时.你无法通过一个函数自动获得它.
#define NEEDS_INFO() \
has_info(__FILE__, __LINE__, __func__)
Run Code Online (Sandbox Code Playgroud)
适当的声明has_info(和C++ 11/C99 __func__ 或类似).
Ker*_* SB 11
这个问题似乎没有明确的,封闭式的答案,所以我只举几个例子.
假设您要打印有关给定类型的信息.编译代码中不存在类型名称,因此它们不可能由语言本身表示(C++扩展除外).这里预处理器必须介入:
#define PRINT_TYPE_INFO(type) do { printf("sizeof(" #type ") = %zu\n", sizeof(type)); } while (false)
PRINT_TYPE_INFO(int);
PRINT_TYPE_INFO(double);
Run Code Online (Sandbox Code Playgroud)
类似地,函数名本身不是变量,因此如果需要生成许多相似的名称,预处理器可以帮助:
#define DECLARE_SYM(name) fhandle libfoo_##name = dlsym("foo_" #name, lib);
DECLARE_SYM(init); // looks up "foo_init()", declares "libfoo_init" pointer
DECLARE_SYM(free);
DECLARE_SYM(get);
DECLARE_SYM(set);
Run Code Online (Sandbox Code Playgroud)
我最喜欢的用途是调度CUDA函数调用并检查它们的返回值:
#define CUDACALL(F, ARGS...) do { e = F(ARGS); if (e != cudaSuccess) throw cudaException(#F, e); } while (false)
CUDACALL(cudaMemcpy, data, dp, s, cudaMemcpyDeviceToHost);
CUDACALL(cudaFree, dp);
Run Code Online (Sandbox Code Playgroud)
因为这是一个开放式问题,这是我经常使用并且发现方便的技巧.
如果你想在自由函数上写一个包装函数,比如说malloc,不修改代码中调用函数的每个实例,那么一个简单的宏就足够了:
#define malloc(X) my_malloc( X, __FILE__, __LINE__, __FUNCTION__)
void* my_malloc(size_t size, const char *file, int line, const char *func)
{
void *p = malloc(size);
printf ("Allocated = %s, %i, %s, %p[%li]\n", file, line, func, p, size);
/*Link List functionality goes in here*/
return p;
}
Run Code Online (Sandbox Code Playgroud)
您可以经常使用此技巧编写自己的内存泄漏检测器等,以进行调试.
虽然这个例子是malloc真的可以重新用于任何独立功能.
如果要将值用作标识符和值,则一个示例是标记粘贴.从msdn链接:
#define paster( n ) printf_s( "token" #n " = %d", token##n )
int token9 = 9;
paster( 9 ); // => printf_s( "token9 = %d", token9 );
Run Code Online (Sandbox Code Playgroud)
在c ++ faq中也有一些情况,尽管可能有替代方案,宏解决方案是最好的方法.一个例子是指向正确宏的成员函数的指针
#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
Run Code Online (Sandbox Code Playgroud)
这使得打电话变得更容易,而不是处理所有尝试与宏一起完成它的各种各样的头发.
int ans = CALL_MEMBER_FN(fred,p)('x', 3.14);
Run Code Online (Sandbox Code Playgroud)
老实说,我只是接受他们的话,并且这样做,但显然随着电话变得更加复杂,情况会变得更糟.
当您需要调用本身时,可以选择从函数返回.
#define MYMACRO(x) if(x) { return; }
void fn()
{
MYMACRO(a);
MYMACRO(b);
MYMACRO(c);
}
Run Code Online (Sandbox Code Playgroud)
这通常用于少量重复代码.