分享

UC头条:c 23中的新功能之五堆栈信息库

 cnzrp 2023-06-09 发布于山西

一、介绍

一般对开发者而言,明晓程序中函数堆栈的调用级次是非常有用的。特别是在遇到一些问题时,可以知道问题产生的函数和此函数被调用的层次,这样就可以基本准确的确定Bug的范围了。所以一个强大的IDE,是所有开发者的一个梦想。也是因为这种情况VistualStudio被称做是“宇宙第一IDE”也不是没有原因的。特别是当和其它的IDE比较时,会发现,这个开发IDE的真得很强大。没有比较就没有伤害。

但是问题来了,这个堆栈信息如何得来?能不能更轻松的为开发者所获取?

在GCC中有一个函数“__builtin_return_address(n)”,通过后面这个n,来得调用级联函数的地址,比如0是当头大哥,1是你当头大哥的当头大哥…。当然,这个builtin函数是一系列的,不是一个,有兴趣可以试一下,在一些特定情况下还是非常有用的。

另外还有几个函数(execinfo.h):

intbacktrace(void**buffer,intsize);char**backtrace_symbols(void*const*buffer,intsize);voidbacktrace_symbols_fd(void*const*buffer,intsize,intfd);

也可以实现堆栈的调用信息查看。

可以看个例子:

#include

#include

#include

#include

#include

voidStackTrace(void)

{

inti,size;

void*buf[128];

size=backtrace(buf,128);

char**str=backtrace_symbols(buf,size);

for(i=0;i

{

printf('curstack:%d#%s\n',i,str[i]);

}

free(str);

}

voidDisplayStack

{

StackTrace;

}

voidCallFunc

{

DisplayStack;

}

intmain

{

CallFunc;

}

运行结果:

curstack:0#./st(+0x11fb)[0x5580e78d21fb]

curstack:1#./st(+0x12ac)[0x5580e78d22ac]

curstack:2#./st(+0x12bc)[0x5580e78d22bc]

curstack:3#./st(+0x12cc)[0x5580e78d22cc]

curstack:4#/lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x7fbcc5629d90]

curstack:5#/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)[0x7fbcc5629e40]

curstack:6#./st(+0x1105)[0x5580e78d2105]

这其实也是对STL中只提供断言(assert等)的一个补充,一切都向着方便易用在发展嘛。

二、c++23中的堆栈信息库

其实这就是Boost.Stacktrace在试用后转正到了STL中,要不老说Boost是STL的前置库不是没有道理的。在c++23中,提出了std::basic_stacktrace:

Definedinheader

template

classbasic_stacktrace;

(1)(sinceC++23)

usingstacktrace=

std::basic_stacktrace>;

(2)(sinceC++23)

namespacepmr{

usingstacktrace=

std::basic_stacktrace>;

}

这等于给c++开发者又一个方便的工具,和前面提到的c++20中的source_location都算是一个工具类的函数。

这个stacktrace是一个容器对象,从前面的分析其实也可以猜测出来,他一定是一层层的通过数据结构来存储着堆栈信息,那么最简单的方式就是用数组,在标准库是那么就是vector了,其中的数据结构是stacktrace_entry,有兴趣可以在“https://en./w/cpp/utility/stacktrace_entry”看到这个条目的详细说明。在这个条目说明中,可以看条提供了to_string,operator<<和hash操作。

其实看到上面说明,是不是可以想一下,在开发者自己以后的开发中,如果有类似的需求,是不是可以拿来主义一下它的设计思想和设计方式呢?

三、应用

下面来看一个简单的例子:

#include

#include

intnested_func(intc)

{

std::cout<

returnc+1;

}

intfunc(intb)

{

returnnested_func(b+1);

}

intmain

{

std::cout<

}

其运行结果为:

msvcoutput:

0>C:\Users\ContainerAdministrator\AppData\Local\Temp\compiler-explorer-compiler20221122-31624-2ja1sf.8ytzw\example.cpp(6):output_s!nested_func+0x1F

1>C:\Users\ContainerAdministrator\AppData\Local\Temp\compiler-explorer-compiler20221122-31624-2ja1sf.8ytzw\example.cpp(12):output_s!func+0x15

2>C:\Users\ContainerAdministrator\AppData\Local\Temp\compiler-explorer-compiler20221122-31624-2ja1sf.8ytzw\example.cpp(15):output_s!main+0xE

3>D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl(288):output_s!__scrt_common_main_seh+0x10C

4>KERNEL32!BaseThreadInitThunk+0x14

5>ntdll!RtlUserThreadStart+0x21

gccoutput:

0#nested_func(int)at/app/example.cpp:7

1#func(int)at/app/example.cpp:13

2#at/app/example.cpp:18

3#at:0

4#at:0

5#

不过可惜是还是那句话,测试这个,得把编译器的版本提到最新,不然是搞不定的。

四、总结

越是学习,越会发现,很多东西其实都是互相影响的。前有Boost,又有gcc扩展相关的堆栈处理,STL对这种有利于自己的事情不可能无动于衷。所以,现在看学习时,有些前辈和牛人推荐大家多看外面的世界,跨一些语言甚至学科,不是没有道理的。但是怎么掌握其中的度,就需要自己把握了。总不能一个学c++的学着学着最后成了一个捕鱼的。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多