提问人:Kaiyakha 提问时间:11/10/2023 最后编辑:Remy LebeauKaiyakha 更新时间:11/11/2023 访问量:78
如何在Visual Studio调用堆栈中读取匿名lambda的名称?
How to read name of anonymous lambdas in Visual Studio call stack?
问:
在调用堆栈中跟踪匿名 lambda 对我来说一直很有挑战性,所以我编写了一些沙盒代码来处理这个问题:
int main() {
[] {
std::cout << "Hello World!\n";
} ();
[] {
std::cout << "Hello World!\n";
} ();
}
在这里,我调用了匿名 lambda。我在 lambda 的主体中放置断点并检查调用堆栈。我看到的是:
`main'::`2'::<lambda_1>::operator()()
`main'::`2'::<lambda_2>::operator()()
我主要是通过在不同的函数或命名空间中使用匿名 lambda 来找出记录的含义。
我无法理解的一件事是这个数字将函数的名称和 lambda 的标签分开。有谁知道这个数字是什么意思?2
main
<lambda_1>
答:
它来自标识嵌套块范围的残缺名称的一部分。示例(godbolt):`2'
void foo()
{
[] { int i = 11; } (); // ??R<lambda_1>@?1??foo@@YAXXZ@QEBA@XZ => `foo'::`2'::<lambda_1>::operator()
[] { int i = 12; } (); // ??R<lambda_2>@?1??foo@@YAXXZ@QEBA@XZ => `foo'::`2'::<lambda_2>::operator()
{
[] { int i = 21; } (); // ??R<lambda_3>@?2??foo@@YAXXZ@QEBA@XZ => `foo'::`3'::<lambda_3>::operator()
[] { int i = 21; } (); // ??R<lambda_4>@?2??foo@@YAXXZ@QEBA@XZ => `foo'::`3'::<lambda_4>::operator()
}
{
[] { int i = 31; } (); // ??R<lambda_5>@?3??foo@@YAXXZ@QEBA@XZ => `foo'::`4'::<lambda_5>::operator()
[] { int i = 31; } (); // ??R<lambda_6>@?3??foo@@YAXXZ@QEBA@XZ => `foo'::`4'::<lambda_6>::operator()
{
[] { int i = 41; } (); // ??R<lambda_7>@?4??foo@@YAXXZ@QEBA@XZ => `foo'::`5'::<lambda_7>::operator()
}
}
{
[] { int i = 51; } (); // ??R<lambda_8>@?5??foo@@YAXXZ@QEBA@XZ => `foo'::`6'::<lambda_8>::operator()
[] { int i = 52; } (); // ??R<lambda_9>@?5??foo@@YAXXZ@QEBA@XZ => `foo'::`6'::<lambda_9>::operator()
}
[] { int i = 13; } (); // ??R<lambda_8>@?1??foo@@YAXXZ@QEBA@XZ => `foo'::`2'::<lambda_8>::operator()
}
因此表示功能级别块,数字越大枚举内部块。
这只是 MSVC 使用的嵌套元素的正常(未记录)修改方案。也就是说,这只是编译器命名符号的方式。`2'
关于修改方案,请参阅例如此链接以获取更多信息。
数字本身来自 中的部分。它是一个“编码数字”。在这里,残缺名称中的数字 1 变成了 2(见此处)。另外,请参阅 此处 了解 LLVM 解构器中的相应代码。`2'
?1
??R<lambda_1>@?1??foo@@YAXXZ@QEBA@XZ
函数级块以损坏的数字(解构)开头,而不是因为在特殊函数中可以有更高级别的块,即构造函数中的初始值设定项列表。例如 (godbolt):1
`2'
0
struct Struct{
void (*func)();
Struct(): func(
// ?<lambda_invoker_cdecl>@<lambda_1_>@?0???0Struct@@QEAA@XZ@SA@XZ
// => `Struct::Struct'::`1'::<lambda_1_>::<lambda_invoker_cdecl>
[](){ int i = 0; }
) {}
};
void foo() {
Struct s;
}
在这里,你会得到一个残缺不全的,因此是一个解缠的.
此外,在功能尝试块中,可能会出现损坏的级别。例如 (godbolt):0
`1'
0
void foo() try
{
}
catch(...)
{
[](){ int i = 111; }();
}
此处的反汇编包含符号 (demangled ) 来表示 .然而,其中的 lambda 具有残缺的嵌套级别 (deangled )。(我猜 +1 用于函数体,+1 用于 catch 声明器。?catch$0@?0??foo@@YAXXZ@4HA
int `void __cdecl foo(void)'::`1'::catch$0
catch
catch
3
`4'
评论
__l2