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
Comments