假设您的C++编译器支持它们,是否有任何特殊原因不使用__FILE__,__LINE__以及__FUNCTION__用于记录和调试目的?
我主要关注的是为用户提供误导性数据 - 例如,由于优化而报告错误的行号或功能,或者因此导致性能下降.
基本上,我可以信任__FILE__,__LINE__并__FUNCTION__以永远做正确的事?
有没有办法在每次调用某个函数时在C或C++中正在运行的进程中转储调用堆栈?我的想法是这样的:
void foo()
{
print_stack_trace();
// foo's body
return
}
Run Code Online (Sandbox Code Playgroud)
其中的print_stack_trace工作方式类似于callerPerl.
或类似的东西:
int main (void)
{
// will print out debug info every time foo() is called
register_stack_trace_function(foo);
// etc...
}
Run Code Online (Sandbox Code Playgroud)
在哪里register_stack_trace_function放置某种内部断点,这将导致在调用时打印堆栈跟踪foo.
在某些标准C库中是否存在这样的事情?
我正在使用GCC在Linux上工作.
我有一个测试运行,基于一些不应该影响此行为的命令行开关,行为不同.我的代码有一个伪随机数生成器,我假设它是基于这些开关被不同地调用的.我希望能够使用每组开关运行测试,并查看随机数生成器是否针对每个开关进行不同的调用.
__FILE__并且__LINE__众所周知.__func__自C99以来有一个.
#include <iostream>
struct Foo {
void Do(){ std::cout << __func__ << std::endl; }
};
int main()
{
std::cout << __func__ << std::endl;
Foo foo; foo.Do();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
将输出
main
Do
Run Code Online (Sandbox Code Playgroud)
是否有任何输出方法名称的宏/关键字Foo::Do?
经过多年使用丑陋的MFC ASSERT宏,我终于决定抛弃它并创建最终的ASSERT宏.
我很好地获取文件和行号,甚至是失败的表达式.我可以显示带有这些的消息框,以及中止/重试/取消按钮.
当我按下Retry时,VS调试器会跳转到包含ASSERT调用的行(而不像某些其他ASSERT函数那样反汇编).所以这一切都非常有效.
但真正酷的是显示失败的函数的名称.
然后我可以决定是否调试它而不试图从文件名中猜出它的功能.
例如,如果我有以下功能:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
ASSERT(lpCreateStruct->cx > 0);
...
}
Run Code Online (Sandbox Code Playgroud)
然后当ASSERT触发时,消息框将显示如下内容:
Function = CMainFrame::OnCreate
Run Code Online (Sandbox Code Playgroud)
那么,在运行时找到当前函数名的最简单方法是什么?
它不应该使用MFC或.NET框架,即使我确实使用这两者.
它应该尽可能便携.
在C++中创建模板函数时,有一种简单的方法可以将模板的类型名称表示为字符串吗?我有一个简单的测试用例来展示我正在尝试做的事情(注意显示的代码不能编译):
#include <stdio.h>
template <typename type>
type print(type *addr)
{
printf("type is: %s",type);
}
int main()
{
int a;
print(&a);
}
// Would like to print something like:
// type is: int
Run Code Online (Sandbox Code Playgroud)
我认为在实例化函数时,typename应该在编译时可用,但我不熟悉模板,我还没有看到将typename作为字符串的方法.
我想这样做的原因是一些printf类型的调试.我有多个线程正在运行,并通过gdb逐步更改程序行为.所以对于某些事情,我想转储有关正在执行哪些函数的信息.这不是太重要,所以如果解决方案过于复杂,我会跳过将此信息添加到我的日志记录功能中.但如果有一种简单的方法可以做到这一点,那将是有用的信息.
我想实现一个函数跟踪器,它将跟踪一个函数执行的时间.我有以下课程: -
class FuncTracer
{
public:
FuncTracer(LPCTSTR strFuncName_in)
{
m_strFuncName[0] = _T('\0');
if( strFuncName_in ||
_T('\0') != strFuncName_in[0])
{
_tcscpy(m_strFuncName,strFuncName_in);
TCHAR strLog[MAX_PATH];
_stprintf(strLog,_T("Entering Func:- <%s>"),m_strFuncName);
LOG(strLog)
m_dwEnterTime = GetTickCount();
}
}
~FuncTracer()
{
TCHAR strLog[MAX_PATH];
_stprintf(strLog,_T("Leaving Func:- <%s>, Time inside the func <%d> ms"),m_strFuncName, GetTickCount()-m_dwEnterTime);
LOG(strLog)
}
private:
TCHAR m_strFuncName[MAX_PATH];
DWORD m_dwEnterTime;
};
void TestClass::TestFunction()
{
// I want to avoid writing the function name maually..
// Is there any macro (__LINE__)or some other way to
// get the function …Run Code Online (Sandbox Code Playgroud) 我正在尝试构建一个调试日志消息函数,该函数记录调用日志消息的位置的文件,行和函数.
#define DEBUG_PANIC(p) CLogging::Debuglogf( "Debug marker (%s) - ::%s() in file: %s(%d)", p, __func__ , __FILE__, __LINE__ );
Run Code Online (Sandbox Code Playgroud)
上面的代码适用于某些编译器,但不是全部.我的代码需要与GCC以及Microsoft Visual工作室交叉兼容.我已添加以下定义以帮助兼容性.
#ifndef __FUNCTION_NAME__
#if defined __func__
// Undeclared
#define __FUNCTION_NAME__ __func__
#elif defined __FUNCTION__
// Undeclared
#define __FUNCTION_NAME__ __FUNCTION__
#elif defined __PRETTY_FUNCTION__
// Undeclared
#define __FUNCTION_NAME__ __PRETTY_FUNCTION__
#else
// Declared
#define __FUNCTION_NAME__ "N/A"
#endif // __func__
#endif // __FUNCTION_NAME__
#define DEBUG_PANIC(p) CLogging::Debuglogf( "Debug marker (%s) - ::%s() in file: %s(%d)", p, __FUNCTION_NAME__, __FILE__, __LINE__ );
Run Code Online (Sandbox Code Playgroud)
上面代码片段的问题在于#else宏在所有编译器上都处于活动状态,而其他宏则没有.换句话说#if defined __func__,在编译器上是假的,其中__func__ …
GCC编译器给我以下宏:
__FILE__ 这样我就可以打印出文件名+目录了.__LINE__ 这样我就可以打印出我要打印的行号.__PRETTY_FUNCTION__ 这样我就可以打印出漂亮的功能名称了Visual C++是否具有这些宏的等价物?一个侧面问题是,这些是C++编译器的标准吗?
我正在使用gcc编译C99代码.我想写一个宏,它将返回一个包含函数名和行号的字符串.
这就是我所拥有的:
#define INFO_MSG __FILE__ ":"__func__"()"
Run Code Online (Sandbox Code Playgroud)
但是,当我编译试图使用此字符串的代码时,例如:
char buff[256] = {'\0'}
sprintf(buff, "Something bad happened here: %s, at line: %d", INFO_MSG, __LINE__);
printf("INFO: %s\n", buff);
Run Code Online (Sandbox Code Playgroud)
我收到以下错误消息:
error: expected ‘)’ before ‘__func__’
Run Code Online (Sandbox Code Playgroud)
我已将问题跟踪到宏.当我__func__从宏中删除时,代码正确编译.
如何修复宏,以便我可以__func__在我的字符串中包含预定义的宏?
当我使用__FUNCTION__宏/变量打印出调试信息时,使用Microsoft C++编译器和gcc时输出的内容似乎有所不同.例如,使用以下简单代码:
class Foo
{
public:
void Bar(int a, int b, int c)
{
printf ("__FUNCTION__ = %s\n", __FUNCTION__);
}
};
int main (void)
{
Foo MyFoo;
MyFoo.Bar();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我得到了使用Microsoft Visual C++编译器
__FUNCTION__ = Foo::Bar
Run Code Online (Sandbox Code Playgroud)
而在使用gcc编译时(在本例中是在Mac上),我得到了
__FUNCTION__ = Bar
Run Code Online (Sandbox Code Playgroud)
第二个例子并不理想,因为我经常有几个类,比方说Init()和Uninit()方法,并且在调试输出跟踪中,几乎不可能知道哪个类被调用,因为类名将丢失.现在,我知道你可以使用__PRETTY_FUNCTION__代替它__FUNCTION__来获得类似的东西
__PRETTY_FUNCTION__ = void Foo::Bar(int, int, int)
Run Code Online (Sandbox Code Playgroud)
这很好,但它对于我需要的东西有点过于冗长,并且对于具有大量参数的函数来说有点长.
所以我的问题是(最后),有没有办法让输出看起来像简单地Foo::Bar使用gcc,如上例所示?