函数之概览

函数

函数是程序员编写的,用于实现功能的代码块.

函数模板

<数据类型>  <函数名称>  (<形式参数说明>)
{
    [语句序列]
    return [表达式];
} 
//<数据类型>为返回值即[表达式]的类型
//函数名称是一个标识符
//形式参数说明是对变量的定义.可以为void,表示无参
//(<函数参数说明>)后面必须有一对{},{}中的内容被称为函数体.
//函数体中可以有语句序列,可以没有.
//return语句必须有,但是[表达式]可以没有.
//有些人数据类型/形式参数说明/return语句可以没有,这些东西你没写也没有报错,编译器没有报错不代表你没有写错.
//编译器编译程序的时候将你的代码处理了一下,加上了这些东西,当然也可能加错.
//各种编译器有不同的处理方式,这些处理方式是透明的.
//如果你不希望不同的编译器编译出来的程序不一样,那么请按照规范来.

其中 <> 表示必须有,[]表示可有可无,根据具体功能决定

只要实现了这个模板,就可以写出来一个语法正确的函数.当然,功能不一定正确.


函数返回值类型

函数返回值被存入%eax寄存器(X86平台),%eax的内容不会被销毁

函数名称

函数名称是用标识符表示的,代表了函数的入口地址
//函数指针的赋值和通过函数指针调用好像很乱,或者说是编译器处理了错误,不过下面的都是合法的
void fun(void){

}

//void (*p0)(void) = fun;//合法
//void (*p1)(void) = &fun;//合法
typedef void(*fun_p)(void);
fun_p *p0 = fun;
fun_p *p1 = &fun;

typedef void(fun_type)(void);
fun_type *p2 = fun;//合法
fun_type *p3 = &fun;//合法

int main(int argc,int ** argv)
{
  (*p0)();//合法
  p0();//合法
  (*p1)();//合法
  p1();//合法
  (*p2);//合法
  p2();//合法
  (*p3);//合法
  p3();//合法
}

形式参数说明

说明的意思是定义
函数调用的时候参数按照从右向左的顺序被定义在栈里面

函数体

函数体实现了函数的功能

一般情况下,在函数入口都要对参数进行检测,而且这些检测最好打包成一个函数

检测的话,有两种方式

//模块内部用if
#include <stdlib.h>
if(expression){
  exit(0);//参数要注意填充为不同的值
}
//对外接口函数用assert
//如果在assert.h中定义了NDEBUG,那么assert函数相当于被注释了
//如果没定义,如果expression为false,那么会调用abort函数,结束进程
//如果没定义,如果expression为true,什么都不做
#include <assert.h>
void assert(scalar expression);

函数接口

函数的接口使用函数的声明即函数原型来体现的
1/起什么名字
  最好见到名字知道功能
2/要多少参数
  函数实现的功能越简单越好,所以参数不可能太多
3/返回值
  是采用值-结果方式还是返回值方式
4/健壮性
  一定要用assert函数
5/通用性
  函数一定要朝小了写
6/移植性
  函数的语法一定要规范

函数调用过程

  • 函数被调用(X86平台)
    1. 下一条指令(函数调用语句的下一条可执行语句)的地址进栈
    2. 函数的最右边的参数入栈,…,最左边的参数入栈(在大多数的C编译器中,参数是由右往左入栈 )
    3. 函数中的局部变量入栈(注意静态变量是不入栈的)
    4. 返回值被复制到%eax寄存器
    5. 局部变量出栈
    6. 参数出栈(先进先出,后进后出)
    7. 执行栈顶指针指向的内存中的地址对应的指令

函数参数的传递

函数参数传递的本质

所有的传参都是复制传参

即在栈中重新定义了一个变量,并对变量赋值为实参的值

值-结果传递

一般传递结构体或者数组的时候用的是值-结果传递方式

因为采用这种方式会减少栈的开销,栈里面只需要定义一个指针就可以了,所以只需要4个字节.

如果不采用这种方式,传递一个结构体变量,那么结构体有多大,栈中就必须定义一个相同的结构体变量,开销大.

数组的传递
int b[] = {3,4,5};
//形参可以多种多样
void test(int a[]){
  a++;//这里的a为一个指针变量,类型为int*,地址为数组b首元素地址
}
void test(int a[N]){//N可以为任何非负整数,编译器并不检查
  a++;//这里的a为一个指针变量,类型为int*,地址为数组b首元素地址
}
void test(int *a){
  a++;//这里的a为一个指针变量,类型为int*,地址为数组b首元素地址
}
//实参只能为数组名
int main(int argc, char ** argv){
  test(b);
}

API

API的中文翻译是应用程序接口,嗯,就是函数接口
有人说还有人说API就是系统调用,这是错的.但可以说系统调用是API.
API是程序员提供的一系列函数接口和具体实现的总称
你如果说你写了一个函数就是一个API,如果你确实这样说的话,嗯,要不就是太牛X,要不就是太傻X.
  • 例如
    你给我了个操作机器的界面,我只要知道我在这个界面上点击什么,会达到什么效果,我不用知道这个功能是怎么实现的,我不用知道这个功能是怎么实现的,我不用知道这个功能是怎么实现的,重要的话说三遍.
API举例
  • 系统调用

  • C库

  • sqlite3库

在各个层面上都有API
  • 在驱动层面,设备树和驱动的配对
  • 在内核层面,调度
  • 在应用层面,c库和系统调用
  • 在沟通层面,电话和手机
  • 在工作方面,指标的达成

嗯,在工作方面不是很切合实际,因为你发现你没有人力资源可以调动.嗯,说的没错,就是这么悲伤.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值