前言今天学习 C 语言函数函数是实现代码模块化最重要的工具。使用函数可以降低程序耦合度减少重复代码提高代码复用能力。在嵌入式项目开发中我们会把传感器读取、外设驱动、数据处理全部封装成函数方便调用与维护。本次学习内容包含函数定义、调用、声明、值传递、递归调用以及数组作为函数参数的传参规则。一、函数基础函数优点降低程序的耦合性关联度减少重复代码让程序模块化增强代码复用性。1. 函数定义格式c返回值类型 函数名(形参表){函数体;}返回值可以是 int、char 等基础数据类型也可以是构造数据类型。用来返回函数最终运算结果。void空类型函数执行完毕不需要返回任何结果时使用 void 作为返回值。函数名标识符遵守标识符命名规则尽量见名知意。习惯以 “动词”“宾语” 命名例如get_max_val();获取最大值。形参表函数执行过程中需要用到的条件。格式数据类型 形参名, 数据类型 形参名, 数据类型 形参名 …注意当函数有明确返回值类型必须写return如果不写 return系统返回内存里随机垃圾值。如果返回值为 void可以不写 return也可以写return;。2. 函数调用格式c函数名(实参表);实参传递给函数的实际条件可以是常量、变量、表达式。实参要求实参的个数和形参的个数必须一一对应。实参和形参的数据类型要一致或者相互兼容。概念区分主调函数发起调用的函数被调函数被别人调用的函数函数执行规则函数不被调用则不会执行调用几次就执行几次。实参和形参名字可以相同也可以不同。3. 函数的声明出现场景被调函数写在主调函数后面编译器报implicit declaration隐式声明警告。两种声明方式在主调函数前面进行函数声明返回值类型 函数名(形参表);多文件开发其他文件想要调用本文件函数也需要做函数声明。4. 函数调用过程栈空间工作机制保护现场函数被调用时把调用位置的下一条指令地址保存到栈空间栈遵循先进后出。恢复现场被调函数执行结束从栈取出保存的地址CPU 回到调用处继续执行后续代码。二、函数的传参 —— 值传递值传递实参向形参做拷贝实参、形参拥有各自独立内存空间。值传递核心特点单向传递只把实参拷贝给形参。在被调函数内部修改形参不会影响主调函数里面原来的实参变量。项目值传递说明内存空间实参、形参各自独立内存数据流向只能实参 → 形参单向拷贝修改效果被调函数修改形参主调函数变量不受影响三、函数的递归调用定义函数直接或者间接调用自身。本质属于循环的一种实现方式。重点规则递归必须设置递归出口没有出口就会变成死循环造成栈溢出。缺点递归调用系统资源开销大于普通循环消耗栈内存嵌入式开发不建议深度递归。简单递归示例逻辑求累加Plain Textmain() → get_sum(5) → get_sum(4) → get_sum(3) → get_sum(2) → get_sum(1)递归出口get_sum(5) → get_sum(4)1 → get_sum(3)1 → get_sum(2)1 → get_sum(1)1→return 1四、一维数组作为函数参数数组名本质是数组首元素的地址。1. 传参书写格式函数定义c返回值类型 函数名(int 数组名[], int len){//函数内部数组使用方式和外部完全一样}函数调用c函数名(数组名,数组长度);2. 数组做函数参数四条注意点形参书写格式int a[]方括号内常量可以写也可以省略。数组名传参传递的不是全部数组拷贝传递的是数组首元素地址形参本质接收一个起始地址。只传数组名无法得到数组长度必须额外把数组长度 len 当做参数传入函数。数组作为函数参数传递给被调函数后函数内部的使用方法和外部的使用方法一样除了sizeof数组名。值传递 vs 数组传参对比传参方式传递内容修改是否影响外部原始数据普通变量值传递变量值拷贝不影响外部变量数组名作为参数数组首元素地址函数内修改数组外部数组同步改变今日学习总结函数三要素返回值、函数名、形参列表void 代表无返回值有返回值的函数必须使用 return。实参与形参个数、类型需要匹配值传递是单向拷贝修改形参不会改变主调函数变量。函数写在调用之后必须提前做函数声明消除隐式声明警告。函数调用依靠栈空间完成保护现场、恢复现场栈遵循先进后出。递归就是函数调用自己一定要写递归出口递归栈开销大嵌入式尽量少用深度递归。数组名做函数参数传递的是首元素地址不是完整数组拷贝必须额外传入数组长度函数内部修改数组外部原始数组会被同步修改。工程实践嵌入式开发中传感器处理、外设驱动全部封装为函数提升代码可读性、复用性。