c++ 编译器如何知道std::函数中捕获的变量的名称?

vhmi4jdf  于 2023-02-01  发布在  其他
关注(0)|答案(1)|浏览(126)

有件事让我很吃惊,那就是如果我在运行时调试期间将捕获lambda(带有重载函数调用操作符的构造对象的语法糖)赋给std::function,编译器会告诉我该函数/类的成员名称:

std::function<void()> callable1;
std::function<void()> callable2;
std::function<void()> callable3;

int main()
{
    int aa = 1;
    int bb = 1;

    callable1 = [dog = aa, cat = bb]() {
        return 5;
    };
    callable2 = [kitchen = aa, lounge = bb]() {
        return 5;
    };
    callable3 = [hammer = aa, sickle = bb]() {
        return 5;
    };


    std::vector < std::function<void()>> callables;
    callables.push_back(callable1);
    callables.push_back(callable2);
    callables.push_back(callable3);
}

我在编译器上看到的是:

这是非常令人印象深刻的,我想知道它是如何做到的。无论使用什么技术,我猜都是一种非常想学习的反射方法,因为c++没有反射特性。有趣的是,在我的机器上,无论是调试模式还是发布模式,std::函数的大小都是64字节,所以我不知道他们是如何将字符串存储为成员的名称的。

fkvaft9z

fkvaft9z1#

编译器如何知道std::函数中捕获的变量的名称?
在Linux上,gcc -g将向ELF executable添加其他部分。

$ readelf -S ./a.out | grep debug
  [29] .debug_aranges    PROGBITS         0000000000000000  0000561c
  [30] .debug_info       PROGBITS         0000000000000000  00005aec
  [31] .debug_abbrev     PROGBITS         0000000000000000  0000cf7e
  [32] .debug_line       PROGBITS         0000000000000000  0000da6c
  [33] .debug_str        PROGBITS         0000000000000000  0000ed66
  [34] .debug_ranges     PROGBITS         0000000000000000  0001499c

这些部分包含DWARF的程序调试信息。例如,在.debug_str中,.debug_info中的调试信息引用了字符串:

$ readelf -x .debug_str ./a.out  | grep kitchen
  0x00005ae0 656e005f 5f6b6974 6368656e 005f5f73 en.__kitchen.__s
$ readelf -x .debug_str ./a.out  | grep dog
  0x00004170 5f646f67 005f5a4e 53743676 6563746f _dog._ZNSt6vecto
$ readelf -x .debug_str ./a.out  | grep sickle
  0x000042a0 64005f5f 7369636b 6c650077 6373746f d.__sickle.wcsto

调试器检查std::function,找到一个函数指针。然后扫描.debug_info中与该指针关联的调试信息的所有条目。然后分析该信息并在IDE中显示分析结果。
我怎样才能得到这些信息?我是指字符串名称和偏移量等?
通常,也是最常见的,您可以通过调试器 * 访问这些信息。调试器是访问这些信息的工具。您可以使用libdwarfefitools从您自己的程序访问这些信息。
例如,您可以在程序和open(argv[0])中包含ELF库,然后解析您自己的ELF可执行文件中的调试部分并显示有关它的信息。通常,在显示有关C++异常的良好堆栈跟踪时,需要检查ELF本身。

相关问题