极少数情况下必须使用MACRO

Ter*_* Li 26 c c++ macros

调试宏可能需要很长时间.我们最好避免使用它们,除非在非常罕见的情况下,常量,函数和模板都不能达到我们想要的效果.

什么是罕见的情况?

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__ 或类似).

  • 用于"操纵程序代码本身"的+1 (8认同)

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)


Alo*_*ave 8

因为这是一个开放式问题,这是我经常使用并且发现方便的技巧.

如果你想在自由函数上写一个包装函数,比如说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真的可以重新用于任何独立功能.


Pau*_*bel 7

如果要将值用作标识符和值,则一个示例是标记粘贴.从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)

老实说,我只是接受他们的话,并且这样做,但显然随着电话变得更加复杂,情况会变得更糟.

这是一个试图单独行动的例子

  • 但是你的成员函数调用中没有强制转换.并且``(object.*ptrToMember)`语法简短明了...... (3认同)

ten*_*our 5

当您需要调用本身时,可以选择从函数返回.

#define MYMACRO(x) if(x) { return; }
void fn()
{
    MYMACRO(a);
    MYMACRO(b);
    MYMACRO(c);
}
Run Code Online (Sandbox Code Playgroud)

这通常用于少量重复代码.