函数
函数是程序员编写的,用于实现功能的代码块.
函数模板
<数据类型> <函数名称> (<形式参数说明>)
{
[语句序列]
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平台)
- 下一条指令(函数调用语句的下一条可执行语句)的地址进栈
- 函数的最右边的参数入栈,…,最左边的参数入栈(在大多数的C编译器中,参数是由右往左入栈 )
- 函数中的局部变量入栈(注意静态变量是不入栈的)
- 返回值被复制到%eax寄存器
- 局部变量出栈
- 参数出栈(先进先出,后进后出)
- 执行栈顶指针指向的内存中的地址对应的指令
函数参数的传递
函数参数传递的本质
所有的传参都是复制传参
即在栈中重新定义了一个变量,并对变量赋值为实参的值
值-结果传递
一般传递结构体或者数组的时候用的是值-结果传递方式
因为采用这种方式会减少栈的开销,栈里面只需要定义一个指针就可以了,所以只需要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库和系统调用
- 在沟通层面,电话和手机
- 在工作方面,指标的达成
嗯,在工作方面不是很切合实际,因为你发现你没有人力资源可以调动.嗯,说的没错,就是这么悲伤.