嵌入式C语言实战开发详解(四)

时间:2021-10-11 19:12:03

一、内存管理

1、你的数据放哪里?

 嵌入式C语言实战开发详解(四)

栈空间:局部变量、函数形参、自动变量(调用后释放)

堆空间:mallocrealloccalloc分配空间

数据段:bss:保存未初始化的全局变量

        rodata:常量

        .data(静态数据区):全局变量、static修饰变量(程序结束后释放)

2、内存的分配方式

(1)从全局数据区分配

(2)在栈上创建

(3)在堆上创建

3、常见的内存错误及对错

(1)内存分配未成功,却使用了它

(2)内存分配虽然成功,但是尚未初始化就引用它

(3)内存分配成功并已经初始化,但操作越过了内存的边界

(4)忘记了释放内存,造成了内存泄漏

(5)释放了内存却继续使用它

4、段错误的调试方法

详情请戳网址:

http://blog.csdn.net/wzhcalex/article/details/51866913

 

二、函数

函数:(1)维护性好,函数要有独立的功能

     (2)迭代开发

     (3)复用性好

函数的调用:

  通过函数名找到函数的入口地址

  给形参分配内存空间

  传值:把实参变量对应的空间的值传给形参

  执行函数体里的语句

  函数返回并释放空间

 

函数的三要素:函数名、函数形参、函数返回值

 

1、函数名(自注释性--可读性)

    1、 一定要写函数声明!

        命名函数名要形成自己的风格!

        命名函数名要体现功能

        动词+名词:get_userinsert_user

        陌生词语不要进行缩写

        先写调用,再写实现

2、函数名也是指针常量,保存函数存放的地址,即函数的入口地址

2、函数参数的传递

1)传参要用对应的类型来接

2)代码示例:

#include<stdio.h>

 

void swap_int(int *left,int *right)

{

    int temp;

    temp = *left;

    *left = *right;

    *right = temp;

 

}

int main()

{

    int left = 5;

    int right = 6;

 

    printf("before swap:left = %d\tright = %d\n",left,right);

 

    swap_int(&left,&right);

 

    printf("after swap:left = %d\tright = %d\n",left,right);

 

    return 0;

}

 

如果只是传值而不是传地址的话,函数返回释放空间,则right、left的值并没有发生交换

这就引来了一个问题:什么时候传值,什么时候传地址呢?

读(不修改)实参变量对应的内存空间的值时,传实参变量名

写(修改)实参变量对应的内存空间的值时,传实参变量的地址(上示例代码即为传地址)

3)传入参数&传出参数:

如果函数接口有指针参数,既可以把指针所指向的数据传给函数使用(称为传入参数),也可以由函数填充指针所指的内存空间,传回给调用者使用(称为传出参数)

代码示例:

嵌入式C语言实战开发详解(四)

 嵌入式C语言实战开发详解(四)

 

(4)主函数的形参:(命令行参数)

#include<stdio.h>

#include<stdlib.h>

 

int main(int argc,char *argv[])

{

    if(argc != 2)

    {

        printf("please input a param!\n");

exit(1);

    }

 

    printf("argc = %d\n",argc);

 

    int i;

 

    for(i = 0; i < argc; i++)

    {

        printf("argv[%d] = %d\n",i,atoi(argv[i]));

    }

    

    return 0;

}

 嵌入式C语言实战开发详解(四)

 

3、函数返回值

(1)不能返回局部变量的地址:局部变量存放于栈空间,函数调用后就释放了

(2)exit1):结束整个程序,头文件为:#include<stdlib.h>

     1:是返回给用户

     通常用来做异常处理,判断哪个exit( )退出,用打印信息的方法

     echo $?

 嵌入式C语言实战开发详解(四)

(3)return 0:返回给操作系统,标志主函数结束

            是规范要求,能够提高操作系统的运行效率,如果不写return 0系统要检查是否是正常退出等等

 

4、企业级函数编写

(1)函数的编码规范:

1、对所调用函数的错误返回码要仔细、全面地处理。

2、防止将函数的参数作为工作变量。

说明:将函数的参数作为工作变量,有可能错误地改变参数内容,所以很危险。对必须改变的参数,最好先用局部变量代之,最后再将该局部变量的内容赋给该参数。

3:函数的规模尽量限制在200行以内。

说明:不包括注释和空格行。

4、一个函数仅完成一件功能。

5、为简单功能编写函数。

说明:虽然为仅用一两行就可完成的功能去编函数好象没有必要,但用函数可使功能明确化,增加程序可读性,亦可方便维护、测试。

6、不要设计多用途面面俱到的函数。

说明:多功能集于一身的函数,很可能使函数的理解、测试、维护等变得困难。

7、尽量不要编写依赖于其他函数内部实现的函数。

说明:此条为函数独立性的基本要求。由于目前大部分高级语言都是结构化的,所以通过具体语言的语法要求与编译器功能,基本就可以防止这种情况发生。但在汇编语言中,由于其灵活性,很可能使函数出现这种情况。

8、避免设计多参数函数,不使用的参数从接口中去掉。

说明:目的减少函数间接口的复杂度。

9、检查函数所有参数输入的有效性。

(2)函数入口参数检查

比如:void * find_string(char *src,char *head,char *tail)

{

if(src == NULL || head == NULL || tail == NULL )

{

    printf(“the param is error!”)

exit(1);

}

}

(3)函数返回值异常处理

详情见上述exit( )

 

5、函数指针、函数指针数组

(1)函数指针

#include<stdio.h>

 

int add(int a,int b)

{

    return a+b;

}

 

int main()

{

    int num1 = 5;

int num2 = 6;

    

int (*p_func)(int,int);

p_func = add; //函数入口地址,倾向于此种

//p_func = &add;整个函数的地址

 

int result = p_func(num1,num2);

 

    printf("result = %d\n",result);

    

    return 0;

}

 

(2)回调函数

#include<stdio.h>

 

int add(int a,int b)

{

    return a+b;

}

int sub(int a,int b)

{

    return a-b;

}

int mul(int a,int b)

{

    return a * b;

}

int cal(int (*p_func)(int,int),int a,int b)

{

    return p_func(a,b);

}

 

int main()

{

    int num1 = 5;

int num2 = 6;

 

int i;

 

    

    int (*func_array[3])(int,int);

    func_array[0] = add;

    func_array[1] = sub;

    func_array[2] = mul;

 

    for(i = 0; i < 3; i++)

    {

        printf("result = %d\n",func_array[i](num1,num2));

    }

    

    return 0;

}

 

回调函数:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。

 

6、可变参数

未完待续