C/C++ macro 通过宏改变函数调用

宏函数macro在有些场景下非常有用,下面的例子记录了如果通过一个变量在编译时,将调用的函数改为带着_dummy后缀的函数。

#ifdef STANDALONE
  #include <redshow.h>
#define REDSHOW_FN_NAME(f) f
#else
  #include <redshow_dummy.h>
  #define REDSHOW_FN_NAME(f) f##_dummy
#endif

#define REDSHOW_FN(f, args) \
  {                         \
    REDSHOW_FN_NAME(f)      \
    args;                   \
  }

REDSHOW_FN(test_fun, (1, 2, 3))

如果定义了STANDALONE则引用redshow.h,这个头文件定义了不带dummy的函数,且REDSHOW_FN_NAME是原始函数的调用。否则,引用redshow_dummy.h。##相当于追加字符串。

REDSHOW_FN接收两个参数,一个是函数名f,一个是参数args。在调用REDSHOW_FN时,第二个参数需要用()包裹起来。

因为本质上,define是在编译阶段,对文件进行预处理。可以通过g++ -E ./a.cpp打印出预处理以后的文件内容。REDSHOW_FN预处理的操作是,将代码中,所有使用REDSHOW_FN的地方,替换为10-13行。而调用REDSHOW_FN_NAME的地方,则并不修改f,而args则原封不动的替换。这样

REDSHOW_FN_NAME(f)      \
args;                   \

实际就变成了test_fun (1, 2, 3);

C++模板类似功能的写法

可以达到类似功能的c++ template的写法:

#define GPUPUNK_SANITIZER_CALL(fn, args...) wrapped_call(fn, #fn, ##args)

template<typename T, typename ...Args>
void wrapped_call(T *f, const char *fn, Args... args){
    SanitizerResult status = f(std::forward<Args>(args)...);
    if (status != SANITIZER_SUCCESS){
        const char* error_string;
        sanitizerGetResultString(status, &error_string);
        PRINT("Sanitizer result error: function %s failed with error %s\\n", fn, error_string);
    }
}

GPUPUNK_SANITIZER_CALL(sanitizerAddPatchesFromFile, "gputrigger_patch.fatbin", context);

wrapped_call的第二个参数是为了将函数名传进去。

Reference

https://stackoverflow.com/questions/806543/c-macros-manipulating-a-parameter-specific-example


文章版权归 FindHao 所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明作者 FindHao 和本文原始地址:
https://findhao.net/easycoding/2591.html

Comments