C语言的灵魂(函数)
2021-02-07 11:16
标签:回收 影响 bind 寄存器 最新 打开 orm 形参 硬件 关于C语言的基础知识:常量、流程控制等等 函数的定义 函数:一组一起执行一个任务的语句。 这里有必要说一下:通常一个较大的程序中会分为若干个模块,一个模块用来实现一个特定的功能,在大多数的编程语言中都有子程序的概念,通常都用子程序来实现模块的功能,在C语言中,子程序的作用就是由函数来完成。在程序设计中通常将一些常用的功能编写成函数,并放在函数库中供别人调用,例如C语言自带一些比较(strcmp)、拷贝(strcopy)等。 学习C语言有两个知识点是必须要学的: 1、函数:理解面向过程和面向对象的切入点 2、指针:帮助我们灵活操作数据,甚至访问硬件资源 函数的声明 函数声明会告诉编译器函数名称及如何调用函数,下面是函数声明的原型: 函数的参数 C语言中,参数分为实参和形参 实参:在调用是传递给函数的参数,实参可以是常量、变量、表达式、函数等。 形参: 它不是实际存在的变量,所以又称为虚拟变量,在定义函数名和函数体时使用,目的是用来接收调用该函数时传入的参数,形参是只在被调用时才分配内存单元,结束后会被释放回收。 形参是函数被调用时用于接收实参值的变量,在调用函数时,有3种向函数传递参数的形式: 1、传值调用:该方法把参数的实际值复制给函数的形参,这种情况修改函数内的形参不会影响实参。 2、传地址调用:通过指针传递方式,形参为指向实参地址的指针,当对形参做指向操作时,就相当于对实参本身进行操作。 3、传引用调用:引用“&”就是别名(相当于每个人都有大名和小名,这里区别于go语言,取址符号),所以程序对引用作出改动,其实就是对目标的改动。 实例: 函数的调用过程 首先完成一个简单的C程序: 使用:gcc -o demo demo.c;来生成可执行文件demo,再通过命令:objdump -d demo > demo.txt,得到该可执行程序的反汇编指令,如下 生成的汇编文件分析: 函数递归 我们以最常见的斐波拉契数列为例: 小编第一次跑这个程序的时候输入了70,发现半天没有响应,打开性能统计cpu占了99%,后来发现在40的时候y都已经上千万了... 可变参数列表 当我们无法列出传递函数的所有实参类型和数目时,我们可以使用省略号参数表例如: 我们之前介绍过参数是以数据结构栈的方式进行存取的,从右到左入栈,如之间将的压栈图,如之前我们调用的额函数(先b参数入栈,再a参数入栈);理论上来说我们只要知道一个参数的地址,那么其他的变量地址都可以进行捕捉到,这里我们讲解哈如果实现可变参数的功能:因为参数是从右到左压栈,当我们不知道参数个数的时候,应该如何开辟栈?通过 代码实例: C语言的灵魂(函数) 标签:回收 影响 bind 寄存器 最新 打开 orm 形参 硬件 原文地址:https://www.cnblogs.com/double-W/p/12775468.htmlextern return_type func_name (para_list);
// 1、extern:是C语言的关键字,表明一个函数的声明,可加可不加
// 2、return_type: 返回值类型
#include
#include
demo: file format Mach-O 64-bit x86-64
Disassembly of section __TEXT,__text:
__text:
100000f20: 55 pushq %rbp // 在linux C中所有的main函数都是被__libc_start_main调用,这里把rbp的地址压栈,每次压栈后,rsp都是指向最新的栈顶
100000f21: 48 89 e5 movq %rsp, %rbp // rsp要么在内存空间中处于一个段的低地址,要么和rbp重合,这里rbp也指向栈顶,重一起表示函数的栈底地址
100000f24: 89 7d fc movl %edi, -4(%rbp)
100000f27: 89 75 f8 movl %esi, -8(%rbp)
100000f2a: 8b 75 fc movl -4(%rbp), %esi
100000f2d: 03 75 f8 addl -8(%rbp), %esi
100000f30: 89 75 f4 movl %esi, -12(%rbp)
100000f33: 8b 45 f4 movl -12(%rbp), %eax
100000f36: 5d popq %rbp
100000f37: c3 retq
100000f38: 0f 1f 84 00 00 00 00 00 nopl (%rax,%rax)
100000f40: 55 pushq %rbp
100000f41: 48 89 e5 movq %rsp, %rbp
100000f44: 48 83 ec 20 subq $32, %rsp
100000f48: c7 45 fc 00 00 00 00 movl $0, -4(%rbp)
100000f4f: c7 45 f8 01 00 00 00 movl $1, -8(%rbp)
100000f56: c7 45 f4 02 00 00 00 movl $2, -12(%rbp)
100000f5d: c7 45 f0 00 00 00 00 movl $0, -16(%rbp)
100000f64: 8b 7d f8 movl -8(%rbp), %edi
100000f67: 8b 75 f4 movl -12(%rbp), %esi
100000f6a: e8 b1 ff ff ff callq -79 <_plus>
100000f6f: 89 45 f0 movl %eax, -16(%rbp)
100000f72: 8b 75 f0 movl -16(%rbp), %esi
100000f75: 48 8d 3d 36 00 00 00 leaq 54(%rip), %rdi
100000f7c: b0 00 movb $0, %al
100000f7e: e8 0d 00 00 00 callq 13
#include
int printf(const char* format ...);
// 这就是printf的函数原型
typedef char* va_list // 该变量用于存储参数
void va_start (....) // 当前参数靠右边的一个参数
type va_arg (...) // 获取到参数
void va_end (...) // 左后一个参数
#include