C++11新特性中的匿名函数Lambda表达式的汇编实现分析(三)-阿里云开发者社区

开发者社区> 青衫无名> 正文

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

简介:
+关注继续查看

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

[ capture ]( params ) -> ret { body }

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

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

    return 0;
}

上面的代码中,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

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

由于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

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

三篇博文的总结:

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

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

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

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

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

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

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

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

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

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

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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
2014秋C++ 第12周项目 C++函数新特征与递归函数
课程主页在http://blog.csdn.net/sxhelijian/article/details/39152703,课程资源在云学堂“贺老师课堂”同步展示,使用的帐号请到课程主页中查看。  【项目1- 阅读程序】阅读下列程序,写出程序的运行结果。上机时运行程序,与你的预期进行对照、理解。如果对运行结果和其背后的原理仍不理解,请通过单步执行的手段跟踪理解。(1)阅读下面两个有静态局部变量
1133 0
7.4 匿名函数和高阶函数
1、匿名函数:没有名字的函数 def sum(s, y):     return x * y m = lambda x, y: x * y print(m) print(m(4, 5)) 2、sorted() 高阶函数 对字典进行排序 mm=dict(a=1,c=10,b=4,d=9) for i in mm:     print(i) for j in mm.
667 0
JSP第四篇【EL表达式介绍、获取各类数据、11个内置对象、执行运算、回显数据、自定义函数、fn方法库】
什么是EL表达式? 表达式语言(Expression Language,EL),EL表达式是用"${}"括起来的脚本,用来更方便的读取对象! EL表达式主要用来读取数据,进行内容的显示! 为什么要使用EL表达式? 为什么要使用EL表达式,我们先来看一下没有EL表达式是怎么样读取对象数据的吧! 在1.
1146 0
针对前段爆出的DNS Cache Poison的一些分析
 http://bbs.chinacissp.com/viewtopic.php?p=81319
558 0
JavaScript立即调用的函数表达式
主要参考知乎上这个问题:javascript 匿名函数有哪几种执行方式  长天之云的回答。 ~(function() {//todo})();!(function() {//todo})(); 对于不太熟悉JavaScript的同学来讲,可能会有两个疑问: 1、!(function() {})();前面为什么要加~、!这些符号? 后面的()是执行一个函数,而(function() {})是一个执行表达式,返回一个匿名函数的引用。
607 0
Python学习笔记:lambda表达式与函数式编程
1,lambda的一般形式是关键字lambda后面跟一个或多个参数,紧跟一个冒号,以后是一个表达式。lambda是一个表达式而不是一个语句。它能够出现在Python语法不允许def出现的地方。作为表达式,lambda返回一个值(即一个新的函数)。
1303 0
lambda匿名函数使用
#!/usr/bin/pythonfun=lambda x:x*x-xprint fun(3)
448 0
javascript 表达式、括号、常用函数和jquery库怎么样实现的分析
(一)javascript表达式 表达式是什么?表达式是对变更进行赋值、更改或计算等操作的语句。它是变量、常量、操作符的综合。根据操作符的不类型,可以分为字符操作表达式、赋值表达式、逻辑表达式、关系表达式、自增自减表达式、位表达式等。
724 0
+关注
3598
文章
840
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载