深入理解C语言的函数调用过程

函数调用原理 聊聊函数调用时 CPU 和内存到底发生了什么事。 阅读详情

深入理解C语言的函数调用过程 

 

    本文主要从进程栈空间的层面复习一下C语言中函数调用的具体过程,以加深对一些基础知识的理解。
    先看一个最简单的程序:
 

点击(此处)折叠或打开 

  1. /*test.c*/
  2. #include <stdio.h>
  3.  
  4.  
  5. int foo1(int m,int n,int p)
  6. {
  7.         int x = m + n + p;
  8.         return x;
  9. }
  10.  
  11. int main(int argc,char** argv)
  12. {
  13.         int x,y,z,result;
  14.         x=11;
  15.         y=22;
  16.         z=33;
  17.         result = foo1(x,y,z);
  18.         printf("result=%d\n",result);
  19.         return 0;
  20. }

    主函数main里定义了4个局部变量,然后调用同文件里的foo1()函数。4个局部变量毫无疑问都在进程的栈空间上,当进程运行起来后我们逐步了解一下main函数里是如何基于栈实现了对foo1()的调用过程,而foo1()又是怎么返回到main函数里的。为了便于观察的粒度更细致一些,我们对test.c生成的汇编代码进行调试。如下:
 

点击(此处)折叠或打开 

  1. .file "test.c"
  2.         .text
  3. .globl foo1
  4.         .type foo1, @function
  5. foo1:
  6.         pushl %ebp
  7.         movl %esp, %ebp
  8.         subl $16, %esp
  9.         movl 12(%ebp), %eax
  10.         movl 8(%ebp), %edx
  11.         leal (%edx,%eax), %eax
  12.         addl 16(%ebp), %eax
  13.         movl %eax, -4(%ebp)
  14.         movl -4(%ebp), %eax
  15.         leave
  16.         ret
  17.         .size foo1, .-foo1
  18.         .section .rodata
  19. .LC0:
  20.         .string "result=%d\n"
  21.         .text
  22. .globl main
  23.         .type main, @function
  24. main:
  25.         pushl %ebp
  26.         movl %esp, %ebp
  27.         andl $-16, %esp
  28.         subl $32, %esp
  29.         movl $11, 16(%esp)
  30.         movl $22, 20(%esp)
  31.         movl $33, 24(%esp)
  32.         movl 24(%esp), %eax
  33.         movl %eax, 8(%esp)
  34.         movl 20(%esp), %eax
  35.         movl %eax, 4(%esp)
  36.         movl 16(%esp), %eax
  37.         movl %eax, (%esp)
  38.         call foo1
  39.         movl %eax, 28(%esp)
  40.         movl $.LC0, %eax
  41.         movl 28(%esp), %edx
  42.         movl %edx, 4(%esp)
  43.         movl %eax, (%esp)
  44.         call printf
  45.         movl $0, %eax
  46.         leave
  47.         ret
  48.         .size main, .-main
  49.         .ident "GCC: (GNU) 4.4.4 20100726 (Red Hat 4.4.4-13)"
  50.         .section .note.GNU-stack,"",@progbits

    上面的汇编源代码和最终生成的可执行程序主体结构上已经非常类似了:

[root@maple 1]# gcc -g -o test test.s 

[root@maple 1]# objdump -D test >testbin 

[root@maple 1]# vi testbin 

 //… 省略部分不相关代码 

80483c0:       ff d0                               call   *%eax 

 80483c2:      c9                                   leave 

 80483c3:      c3                                   ret 

  

080483c4 :

 80483c4:       55                                  push  %ebp 

 80483c5:      89 e5                               mov   %esp,%ebp 

 80483c7:      83 ec 10                          sub    $0x10,%esp 

 80483ca:      8b 45 0c                          mov    0xc(%ebp),%eax 

 80483cd:      8b 55 08                         mov   0x8(%ebp),%edx 

 80483d0:      8d 04 02                         lea    (%edx,%eax,1),%eax 

 80483d3:      03 45 10                         add    0x10(%ebp),%eax 

 80483d6:      89 45 fc                          mov    %eax,-0x4(%ebp) 

 80483d9:      8b 45 fc                          mov    -0x4(%ebp),%eax 

 80483dc:      c9                                   leave 

 80483dd:      c3                                   ret 

  

080483de 

:

 80483de:      55                                     push   %ebp 

 80483df:      89 e5                                 mov   %esp,%ebp 

 80483e1:      83 e4 f0                            and    $0xfffffff0,%esp 

 80483e4:      83 ec 20                           sub    $0x20,%esp 

 80483e7:      c7 44 24 10 0b 00 00       movl   $0xb,0x10(%esp) 

 80483ee:      00 

 80483ef:      c7 44 24 14 16 00 00        movl   $0x16,0x14(%esp) 

 80483f6:      00 

 80483f7:      c7 44 24 18 21 00 00        movl   $0x21,0x18(%esp) 

 80483fe:      00 

 80483ff:      8b 44 24 18                      mov    0x18(%esp),%eax 

 8048403:      89 44 24 08                    mov    %eax,0x8(%esp) 

 8048407:      8b 44 24 14                    mov    0x14(%esp),%eax 

 804840b:      89 44 24 04                    mov    %eax,0x4(%esp) 

 804840f:      8b 44 24 10                     mov    0x10(%esp),%eax 

 8048413:      89 04 24                         mov    %eax,(%esp) 

 8048416:       e8 a9 ff ff ff                     call  80483c4

 804841b:      89 44 24 1c                     mov    %eax,0x1c(%esp) 

 804841f:      b8 04 85 04 08                 mov    $0x8048504,%eax 

 8048424:      8b 54 24 1c                     mov    0x1c(%esp),%edx 

 8048428:      89 54 24 04                     mov    %edx,0x4(%esp) 

 804842c:      89 04 24                         mov    %eax,(%esp) 

 804842f:      e8 c0 fe ff ff                     call   80482f4

 8048434:      b8 00 00 00 00              mov    $0x0,%eax 

 8048439:       c9                                  leave 

 804843a:      c3                                  ret 

 804843b:      90                                 nop 

 804843c:      90                                 nop 

 //… 省略部分不相关代码


    用GDB调试可执行程序test:


    在main函数第一条指令执行前我们看一下进程test的栈空间布局。因为我们最终的可执行程序是通过glibc库启动的,在main的第一条指令运行前,其实还有很多故事的,这里就不展开了,以后有时间再细究,这里只要记住一点:main函数执行前,其进程空间的栈里已经有了相当多的数据。我的系统里此时栈顶指针esp的值是0xbffff63c,栈基址指针ebp的值0xbffff6b8,指令寄存器eip的值是0x80483de正好是下一条马上即将执行的指令,即main函数内的第一条指令“push %ebp”。那么此时,test进程的栈空间布局大致如下:

    然后执行如下三条指令:
 

点击(此处)折叠或打开 

  1. 25 pushl %ebp         //将原来ebp的值0xbffff6b8如栈,esp自动增长4字节
  2. 26 movl %esp, %ebp    //用ebp保存当前时刻esp的值
  3. 27 andl $-16, %esp    //内存地址对其,可以忽略不计

   执行完上述三条指令后栈里的数据如上图所示,从0xbffff630到0xbffff638的8字节是为了实现地址对齐的填充数据。此时ebp的值0xbffff638,该地址处存放的是ebp原来的值0xbffff6b8。详细布局如下:

   第28条指令“subl  $32,%esp”是在栈上为函数里的本地局部变量预留空间,这里我们看到main主函数有4个int型的变量,理论上说预留16字节空间就可以了,但这里却预留了32字节。GCC编译器在生成汇编代码时,已经考虑到函数调用时其输入参数在栈上的空间预留的问题,这一点我们后面会看到。当第28条指令执行完后栈空间里的数据和布局如下:

    然后main函数里的变量x,y,z的值放到栈上,就是接下来的三条指令:

 

点击(此处)折叠或打开 

  1. 29 movl $11, 16(%esp)
  2. 30 movl $22, 20(%esp)
  3. 31 movl $33, 24(%esp)


   这是三条寄存器间接寻址指令,将立即数11,22,33分别放到esp寄存器所指向的地址0xbffff610向高位分别偏移16、20、24个字节处的内存单元里,最后结果如下:


   注意:这三条指令并没有改变esp寄存器的值。

   接下来main函数里就要为了调用foo1函数而做准备了。由于mov指令的两个操作数不能都是内存地址,所以要将x,y和z的值传递给foo1函数,则必须借助通用寄存器来完成,这里我们看到eax承担了这样的任务:
 

点击(此处)折叠或打开 

  1. 32 movl 24(%esp), %eax
  2. 33 movl %eax, 8(%esp)
  3. 34 movl 20(%esp), %eax
  4. 35 movl %eax, 4(%esp)
  5. 36 movl 16(%esp), %eax
  6. 37 movl %eax, (%esp)

 


    当foo1函数所需要的所有输入参数都已经按正确的顺序入栈后,紧接着就需要调用call指令来执行foo1函数的代码了。前面的博文说过,call指令执行时分两步:首先会将call指令的下一条指令(movl  %eax,28(%esp))的地址(0x0804841b)压入栈,然后跳转到函数foo1入口处开始执行。当第38条指令“call foo1”执行完后,栈空间布局如下:

   call指令自动将下一条要执行的指令的地址0x0804841b压入栈,栈顶指针esp自动向低地址处“增长”4字节。所以,我们以前在C语言里所说的函数返回地址,应该理解为:当被调用函数执行完之后要返回到它的调用函数里下一条马上要执行的代码的地址。为了便于观察,我们把foo1函数最后生成指令再列出来:
 

点击(此处)折叠或打开 

  1. 3 .globl foo1
  2. 4           .type foo1, @function
  3. 5 foo1:
  4. 6           pushl %ebp
  5. 7           movl %esp, %ebp
  6. 8           subl $16, %esp
  7. 9           movl 12(%ebp), %eax
  8. 10          movl 8(%ebp), %edx
  9. 11          leal (%edx,%eax), %eax
  10. 12          addl 16(%ebp), %eax
  11. 13          movl %eax, -4(%ebp)
  12. 14          movl -4(%ebp), %eax
  13. 15          leave
  14. 16          ret
  15. 17          .size foo1, .-foo1 

    进入到foo1函数里,开始执行该函数里的指令。当执行完第6、7、8条指令后,栈里的数据如下。这三条指令就是汇编层面函数的“序幕”,分别是保存ebp到栈,让ebp指向当前栈顶,然后为函数里的局部变量预留空间:

   接下来第9和第10条指令,也并没有改变栈上的任何数据,而是将函数输入参数列表中的的x和y的值分别转载到eax和edx寄存器,和main函数刚开始时做的事情一样。此时eax=22、edx=11。然后用了一条leaf指令完成x和y的加法运算,并将运算结果存在eax里。第12条指令“addl 16(%ebp), %eax”将第三个输入参数p的值,这里是实参z的值为33,同样用寄存器间接寻址模式累加到eax里。此时eax=11+22+33=66就是我们最终要得计算结果。


   因为我们foo1()函数的C代码中,最终计算结果是保存到foo1()里的局部变量x里,最后用return语句将x的值通过eax寄存器返回到mian函数里,所以我们看到接下来的第13、14条指令有些“多此一举”。这足以说明gcc人家还是相当严谨的,C源代码的函数里如果有给局部变量赋值的语句,生成汇编代码时确实会在栈上为本地变量预留的空间里的正确位置为其赋值。当然gcc还有不同级别的优化技术来提高程序的执行效率,这个不属于本文所讨论的东西。让我们继续,当第13、14条指令执行完后,栈布局如下:

   将ebp-4的地址处0xbffff604(其实就是foo1()里的第一个局部参数x的地址)的值设置为66,然后再将该值复制到eax寄存器里,等会儿在main函数里就可以通过eax寄存器来获取最终的计算结果。当第15条指令leave执行完后,栈空间的数据和布局如下:

    我们发现,虽然栈顶从0xbffff5f8移动到0xbffff60c了,但栈上的数据依然存在。也就是说,此时你通过esp-8依旧可以访问foo1函数里的局部变量x的值。当然,这也是说得通的,因为函数此时还没有返回。我们看栈布局可以知道当前的栈顶0xbffff60c处存放的是下一条即将执行的指令的地址,对照反汇编结果可以看到这正是main函数里的第18条指令(在整个汇编源文件test.s里的行号是39)“movl  %eax, 28(%esp)”。leave指令其实完成了两个任务:
   1、将栈上为函数预留的空间“收回”;
   2、恢复ebp;

   也就是说leave指令等价于下面两条指令,你将leave替换成它们编译运行,结果还是对的: 

 

点击(此处)折叠或打开 

  1. movl %ebp,%esp
  2. popl %ebp 

 


   前面我们也说过,ret指令会自动到栈上去pop数据,相当于执行了“popl %eip”,会使esp增大4字节。所以当执行完第16条指令ret后,esp从0xbffff60c增长到0xbffff610处,栈空间结构如下:

   现在已经从foo1里返回了,但是由于还没执行任何push操作,栈顶“上部”的数据依旧还是可以访问到了,即esp-12的值就是foo1里的局部变量x的值、esp-4的值就是函数的返回地址,当执行第39条指令“movl %eax,28(%esp)”后栈布局变成下面的样子:

   第39条指令就相当于给main里的result变量赋值66,如上红线标注的地方。接下来main函数里要执行printf("result=%d\n",result)语句了,而printf又是C库的一个常用的输出函数,这里就又会像前面调用foo1那样,初始化栈,然后用“call printf的地址”来调用C函数。当40~43这4条指令执行完后,栈里的数据如下:
 

点击(此处)折叠或打开 

  1. 40 movl $.LC0, %eax
  2. 41 movl 28(%esp), %edx
  3. 42 movl %edx, 4(%esp)
  4. 43 movl %eax, (%esp)

   上图为了方便理解,将栈顶的0x08048504替换了成字符串“result=%d\n”,但进程实际运行时此时栈顶esp的值是字符串所在的内存地址。当第44条指令执行完后,栈布局如下:

   由于此时栈已经用来调用printf了,所以栈顶0xbffff610“以上”部分的空间里就找不到foo1的任何影子了。最后在main函数里,当第46、47条指令执行完后栈的布局分别是:

    当main函数里的ret执行完,其实是返回到了C库里继续执行剩下的清理工作。
   所以,最后关于C的函数调用,我们可以总结一下:
   1、函数输入参数的入栈顺序是函数原型中形参从右至左的原则;
   2、汇编语言里调用函数通常情况下都用call指令来完成;
   
3、汇编语言里的函数大部分情况下都符合以下的函数模板:
 

点击(此处)折叠或打开 

  1. .globl fun_name
  2. .type fun_name, @function
  3. fun_name:
  4.         pushl %ebp
  5.         movl %esp, %ebp
  6.         <函数主体代码> 
  7.         leave
  8.         ret 


   如果我们有个函数原型:int funtest(int x,int y int z char* ptr),在汇编层面,当调用它时栈的布局结构一般是下面这个样子:


    而有些资料上将ebp指向函数返回地址的地方,这是不对的。正常情况下应该是ebp指向old ebp才对,这样函数末尾的leave和ret指令才可以正常工作。

三维跨孔电磁波CT数据可视化框架搭建 利用matlab实现对跨孔电磁波CT实测数据反演,并搭建了三维CT数据可视化框架,可装填实测CT反演数据。 阅读详情

相关推荐

Arduino MLX90393磁力计驱动库:高精度三轴霍尔传感器开发指南

三轴霍尔效应磁力计是嵌入式系统中实现无接触角度检测、电子罗盘与电流传感的核心器件。其工作原理基于霍尔电压随外磁场矢量变化的物理特性,通过I²C接口输出高分辨率(16/20-bit)XYZ轴原始数据,并集成温度补偿与数字滤波功能。技术价值体现在确定性响应、低功耗(典型0.5 μA待机)及强抗干扰能力,适用于电池供电设备与实时操作系统环境。典型应用场景包括电机位置反馈、永磁体旋转角度解算、工业编码器和地磁导航。本库专为Arduino生态优化,深度封装MLX90393寄存器协议与自校准流程,同时兼容STM32、E

weixin_29363791的博客 641

C语言函数调用的过程图解深入剖析

局部变量的创建过程、为啥局部变量不初始化就输出类似于烫烫烫这样的乱码,以及局部变量存放在哪些地方。函数栈帧创建和销毁过程。

我的主页 6480

分位数映射数据后处理-Quantile Mapping后处理 (R语言)

统计后处理器基本上是统计模型,将观察到的关注变量与从气象或水文模型的直接模型输出(DMO)导出的适当预测变量相关联。统计后处理的重要性早已在气象预报中得到认可。早期的工作包括完善的预测(perfect prognosis),模型输出统计(MOS)和模拟方法(analog method)等模型。 近年来,已经提出了许多其他后处理方法,包括秩直方图校准(rank histogram calibrati...

水滴石穿,绳锯木断 1万+

【C语言】深入理解C语言的函数调用过程

深入理解C语言的函数调用过程 我们先来看一段简单的C语言代码: #include &lt;stdio.h&gt; int Add(int x, int y) { int z = 0; z = x + y; return z; } int main() { int a = 10; int b = 20; int ret =...

csdn_baotai的博客 2453

10X Visium空间转录组学入门:从芯片结构到数据分析全流程解析(附避坑指南)

本文全面解析10X Visium空间转录组学技术,从芯片物理结构、探针化学原理到湿实验全流程操作与避坑指南,并详细介绍了从FASTQ数据到空间可视化的核心分析流程。文章旨在帮助科研人员跨越从理论到实操的鸿沟,掌握从样本准备、文库构建到使用Space Ranger和Seurat进行数据分析与可视化的完整路径,为组织生物学研究提供清晰的实践指引。

weixin_29306011的博客 163

Opencv2.4.9源码分析——HoughCircles

图形可以用一些参数进行表示,标准霍夫变换的原理就是把图像空间转换成参数空间(即霍夫空间),例如霍夫变换的直线检测就是在距离-角度空间内进行检测。圆可以表示成: (x-a)2+(y-b)2=r2                   (1) 其中a和b表示圆心坐标,r表示圆半径,因此霍夫变换的圆检测就是在这三个参数组成的三维空间内进行检测。 原则上,霍夫变换可以检测任何形状。但复杂的形状需要的

赵春江的专栏 3万+

C语言基础知识--函数调用过程详解(包括参数和返回值传递)

C语言函数调用过程详解,用汇编分析函数调用过程中如何传递参数和返回值,以及调用子函数过程中栈的操作

BIN-XYB的博客 2970

OneNet新版MQTT+OneJSON接入全指南

物联网云平台设备接入是嵌入式系统与云端协同的基础能力,其核心依赖于标准化通信协议与统一数据模型。MQTT作为轻量级发布/订阅协议,凭借低带宽占用和高可靠性,成为边缘设备上云的主流选择;而物模型(Thing Model)则定义了设备能力的数字契约,支撑数据语义化与平台自治管理。OneNet新版强制采用MQTT+OneJSON协议栈,不仅提升数据解析一致性与安全认证强度,更推动开发范式从‘协议适配’转向‘模型驱动’。该架构广泛适用于环境监测、智能表计、工业传感等场景,尤其利好基于ESP8266、STM32等资源

weixin_42599558的博客 361

c语言调用函数的作用,深入理解C语言的函数调用过程

本文主要从进程栈空间的层面复习一下C语言中函数调用的具体过程,以加深对一些基础知识的理解。先看一个最简单的程序:/*test.c*/#include int foo1(int m,int n,int p){int x = m + n + p;return x;}int main(int argc,char** argv){int x,y,z,result;x=11;y=22;z=33;result...

weixin_36163504的博客 1371

ch32v103xx 烧写

烧写方式 串口uart, usb,swd(wch link)但不建议按此使用,参官方说明。

qq_39239990的博客 637

blender中合并的模型,在threejs中显示多个mesh;blender多材质烘培成一个材质

5、优化项(省略此步骤,直接进行步骤6),进入到视图着色方式(此时没有灯光,整体偏暗,如果不调整灯光,烘培出来的材质也偏暗,因此此步骤为优化项,通畅建议调整)。在右边栏进入世界环境,调整颜色。7、烘焙成功之后,新建一个材质,将第三步创建的纹理图像作为材质的纹理,连接到基础色,并把模型的材质改为此材质,其他的材质全部删除。2、处理uv,在侧边栏选择数据-uv贴图,选中使用的uv,进入编辑模式,全选,键盘u,选择智能uv投射。3、处理材质,在侧边栏选择材质,进入着色,在着色器编辑器新建一个图像纹理,新建图像。

AllBluefm的专栏 2529

深入理解C语言的函数调用过程 【转】

转自:http://blog.chinaunix.net/uid-25909619-id-4240084.html 原文地址:深入理解C语言的函数调用过程 作者:wjlkoorey258       本文主要从进程栈空间的层面复习一下C语言中函数调用的具体过程,以加深对一些基础知识的理解。    先看一个最简单的程序: 点击(此处)折叠或打开 /*test.c...

weixin_34362875的博客 95

人工智能在高中教育中的应用现状剖析与挑战应对

人工智能在高中教育中的应用现状剖析与挑战应对

燕鹏 1338

深入理解 C 语言的函数调用过程

来源:wjlkoorey链接:http://blog.chinaunix.net/uid-23069658-id-3981406.html本文主要从进程栈空间的层面复习一下C语言中函数调用的具体过程,以加深对一些基础知识的理解。先看一个最简单的程序:主函数main里定义了4个局部变量,然后调用同文件里的foo1()函数。4个局部变量毫无疑问都在进程的栈空间上,当进程运行起来后我们逐步了解一下ma...

weixin_30679823的博客 211

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

上一篇: 内存区域的划分和分配
下一篇: linux c/c++ GDB教程详解
csshuke
博客等级 码龄16年 1517粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值