Aar*_*ron 47
这是您经常使用的解决方案.它的优点是不需要更改实际的功能代码(不添加对stackwalk函数的调用,更改参数以传递函数名称,或链接到额外的库).要使其正常工作,您只需使用一些预处理器魔法:
// orignal function name was 'FunctionName'
void FunctionNameReal(...)
{
// Do Something
}
#undef FunctionName
#define FunctionName printf("Calling FunctionName from %s\n",__FUNCTION__);FunctionNameReal
Run Code Online (Sandbox Code Playgroud)
您必须暂时重命名您的功能,但请参阅下面的注释以获取更多建议.这将在printf()调用函数的每个点处产生一个语句.显然,你必须做一些安排,如果你正在调用一个成员函数,或者需要捕获返回值(比如传递函数调用和 __FUNCTION__ 返回相同类型的自定义函数......),但基本技术是相同.您可能希望使用__LINE__和/ __FILE__或其他一些预处理器宏,具体取决于您拥有的编译器.(此示例专门用于MS VC++,但可能适用于其他人.)
此外,您可能希望将这样的内容放在由#ifdef警卫包围的标题中,以有条件地将其打开,这也可以处理为您重命名实际功能.
我收到了扩大答案的请求.事实证明,我上面的例子有点简单.以下是使用C++处理此问题的一些完整编译示例.
使用classwith operator()使得这非常简单.第一种技术适用于具有和不具有返回值的独立功能. operator()只需要反映与相关函数相同的返回值,并具有匹配的参数.
您可以g++ -o test test.cpp使用非报告版本和g++ -o test test.cpp -DREPORT显示调用者信息的版本进行编译.
#include <iostream>
int FunctionName(int one, int two)
{
static int calls=0;
return (++calls+one)*two;
}
#ifdef REPORT
// class to capture the caller and print it.
class Reporter
{
public:
Reporter(std::string Caller, std::string File, int Line)
: caller_(Caller)
, file_(File)
, line_(Line)
{}
int operator()(int one, int two)
{
std::cout
<< "Reporter: FunctionName() is being called by "
<< caller_ << "() in " << file_ << ":" << line_ << std::endl;
// can use the original name here, as it is still defined
return FunctionName(one,two);
}
private:
std::string caller_;
std::string file_;
int line_;
};
// remove the symbol for the function, then define a new version that instead
// creates a stack temporary instance of Reporter initialized with the caller
# undef FunctionName
# define FunctionName Reporter(__FUNCTION__,__FILE__,__LINE__)
#endif
void Caller1()
{
int val = FunctionName(7,9); // <-- works for captured return value
std::cout << "Mystery Function got " << val << std::endl;
}
void Caller2()
{
// Works for inline as well.
std::cout << "Mystery Function got " << FunctionName(11,13) << std::endl;
}
int main(int argc, char** argv)
{
Caller1();
Caller2();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
样本输出(报告)
Reporter: FunctionName() is being called by Caller1() in test.cpp:44
Mystery Function got 72
Reporter: FunctionName() is being called by Caller2() in test.cpp:51
Mystery Function got 169
Run Code Online (Sandbox Code Playgroud)
基本上,在任何FunctionName发生的地方,它都会替换它Reporter(__FUNCTION__,__FILE__,__LINE__),其净效果是预处理器通过立即调用operator()函数来编写一些对象实例.您可以使用查看预处理器替换的结果(以gcc为单位)g++ -E -DREPORT test.cpp.Caller2()成为:
void Caller2()
{
std::cout << "Mystery Function got " << Reporter(__FUNCTION__,"test.cpp",51)(11,13) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
你可以看到,__LINE__并__FILE__已取代.(我不确定为什么__FUNCTION__仍然在输出中显示为了诚实,但编译版本报告正确的功能,因此它可能与多次传递预处理或gcc错误有关.)
这有点复杂,但与前面的例子非常相似.我们也在替换类,而不是仅仅替换对函数的调用.
与上面的示例类似,您可以g++ -o test test.cpp使用非报告版本和g++ -o test test.cpp -DREPORT显示调用者信息的版本进行编译.
#include <iostream>
class ClassName
{
public:
explicit ClassName(int Member)
: member_(Member)
{}
int FunctionName(int one, int two)
{
return (++member_+one)*two;
}
private:
int member_;
};
#ifdef REPORT
// class to capture the caller and print it.
class ClassNameDecorator
{
public:
ClassNameDecorator( int Member)
: className_(Member)
{}
ClassNameDecorator& FunctionName(std::string Caller, std::string File, int Line)
{
std::cout
<< "Reporter: ClassName::FunctionName() is being called by "
<< Caller << "() in " << File << ":" << Line << std::endl;
return *this;
}
int operator()(int one, int two)
{
return className_.FunctionName(one,two);
}
private:
ClassName className_;
};
// remove the symbol for the function, then define a new version that instead
// creates a stack temporary instance of ClassNameDecorator.
// FunctionName is then replaced with a version that takes the caller information
// and uses Method Chaining to allow operator() to be invoked with the original
// parameters.
# undef ClassName
# define ClassName ClassNameDecorator
# undef FunctionName
# define FunctionName FunctionName(__FUNCTION__,__FILE__,__LINE__)
#endif
void Caller1()
{
ClassName foo(21);
int val = foo.FunctionName(7,9); // <-- works for captured return value
std::cout << "Mystery Function got " << val << std::endl;
}
void Caller2()
{
ClassName foo(42);
// Works for inline as well.
std::cout << "Mystery Function got " << foo.FunctionName(11,13) << std::endl;
}
int main(int argc, char** argv)
{
Caller1();
Caller2();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是示例输出:
Reporter: ClassName::FunctionName() is being called by Caller1() in test.cpp:56
Mystery Function got 261
Reporter: ClassName::FunctionName() is being called by Caller2() in test.cpp:64
Mystery Function got 702
Run Code Online (Sandbox Code Playgroud)
这个版本的高点是一个装饰原始类的类,以及一个返回对类实例的引用的替换函数,允许operator()执行实际的函数调用.
希望有人帮助!
Rus*_*ord 19
GCC版本≥4.8你可以使用__builtin_FUNCTION- 不要混淆__FUNCTION__和类似 - 它似乎有点模糊.
例:
#include <cstdio>
void foobar(const char* str = __builtin_FUNCTION()){
std::printf("called by %s\n", str);
}
int main(){
foobar();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
called by main
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
58029 次 |
| 最近记录: |