C++11新特性中的匿名函数Lambda表达式的汇编实现分析(三)

简介:

Lambda表达式中较复杂的形式如下:

[ capture ]( params ) -> ret { body }
AI 代码解读

现在我们构造一个简单的Lambda闭包函数进行分析:

int main()
{
    int c = 10;
    auto lambda = [&](int a, int b)->int{
        return a + b - c;
    };
    int r = lambda(1, 2);

    return 0;
}
AI 代码解读

上面的代码中,lambda表达式要求传递两个参数a和b,并按引用捕获c,计算后的结果返回给r。

相应的汇编码如下:

int c = 10;
 mov         dword ptr [ebp-8],0Ah  
    auto lambda = [&](int a, int b)->int{
        return a + b - c;
    };
 lea         eax,[ebp-8]  
 push        eax  
 lea         ecx,[ebp-14h]  
 call        010E13B0  
    int r = lambda(1, 2);
 push        2  
 push        1  
 lea         ecx,[ebp-14h]  
 call        010E1400  
 mov         dword ptr [ebp-20h],eax  

    return 0;
 xor         eax,eax
AI 代码解读

显而易见的,和前面两篇文中的一样,这里仅作简要说明:

由于Lambda表达式中捕获了c,因此这里第一个lea指令,向复制函数传递了c的地址,第二条lea指令向复制函数传递了this用于记录捕获对象的地址,

发生调用时,两个push按照stdcall的方式,从右向左压栈。并向表达式传入了this用于寻址。

lambda调用完毕的返回值默认放在eax中,因此,这里最后一个mov意思是将闭包的函数返回值写入r中。

那么,再看看闭包内如何处理传入参数的以及如何返回的?其实就像普通函数一样的原理,以前的博文也说到过函数调用的汇编原理,这里再简单说说吧。

pop         ecx  
 mov         dword ptr [ebp-8],ecx  
        return a + b - c;
 mov         eax,dword ptr [ebp+8]  
 add         eax,dword ptr [ebp+0Ch]  
 
 mov         ecx,dword ptr [ebp-8]  
 mov         edx,dword ptr [ecx]  
 sub         eax,dword ptr [edx]
参数[ebp+8] = a ;[ebp+0Ch] = b
AI 代码解读

eax往往是放临时量,edx往往是放地址,按照这个经验,很容易看出,后面两个mov取出this(得到的是&c)然后从a+b中减去(&c),结果放在eax中,ret返回后供主函数中的r获取之。

三篇博文的总结:

C++11中lambda表达式在形式上改变了函数的书写,使函数调用更加简洁灵活,闭包函数也是许多高级语言的特性之一。

Lambda表达式并不是一个神奇的东西,万变不离其宗,他仍然是以一个函数的形式存在于汇编中,底层处理和普通函数基本一样。

Lambda表达式和普通函数在源程序的实现上有不同:

Lambda表达式通常被作为参数传递给另一个函数,它本身作为callback,以此避免在其他地方写出完整函数或使用函数指针。

Lambda表达式和普通函数在汇编层上的实现基本相同:

最特殊的地方是,当闭包中要使用本身作用域外的变量时,需要进行“捕获”,而捕获其实是通过另一个隐藏的(源代码不可见),我叫它复制函数(或者叫准备函数吧)来实现的,具体实现根据捕获方式的不同而不同,大体上是一系列赋值语句。

闭包中通过传入的this指针(不能直接使用)对捕获的变量或者对象进行操作。
AI 代码解读

关于捕获方式中的按值或者按引用的概念,和普通函数一致。

好了,说到这里,Lambda表达式的底层实现基本说到,本系列博文均属原创,感谢开源中国OSChina提供这样一个学习交流的平台,读者如有其它见解,欢迎评论!

最后送大家一句话,也是原创的。

我们不需要重复造轮子,但是我们必须具有造轮子的能力。

目录
打赏
0
0
0
0
14291
分享
相关文章
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
40 12
为什么C/C++编译腰要先完成汇编
C/C++ 编译过程中先生成汇编语言是历史、技术和实践的共同选择。历史上,汇编语言作为成熟的中间表示方式,简化了工具链;技术上,分阶段编译更高效,汇编便于调试和移植;实践中,保留汇编阶段降低了复杂度,增强了可移植性和优化能力。即使在现代编译器中,汇编仍作为重要桥梁,帮助开发者更好地理解和优化代码。
72 25
为什么C/C++编译腰要先完成汇编
【C++11】lambda表达式
C++11 引入了 Lambda 表达式,这是一种定义匿名函数的方式,极大提升了代码的简洁性和可维护性。本文详细介绍了 Lambda 表达式的语法、捕获机制及应用场景,包括在标准算法、排序和事件回调中的使用,以及高级特性如捕获 `this` 指针和可变 Lambda 表达式。通过这些内容,读者可以全面掌握 Lambda 表达式,提升 C++ 编程技能。
289 3
C++ 11新特性之Lambda表达式
C++ 11新特性之Lambda表达式
47 0
|
8月前
|
c++中 lambda 表达式 解析
c++中 lambda 表达式 解析
77 0
c++中 lambda 表达式 解析
汇编语言----X86汇编指令
汇编语言----X86汇编指令
498 2
【ARM汇编速成】零基础入门汇编语言之指令集(三)
【ARM汇编速成】零基础入门汇编语言之指令集(三)
169 0
【ARM汇编速成】零基础入门汇编语言之指令集(二)
【ARM汇编速成】零基础入门汇编语言之指令集(二)
615 0
几组汇编指令的比较
几组汇编指令的比较

热门文章

最新文章

下一篇
oss创建bucket