嵌入式C语言(二)

二、.h文件的作用

在分析.h文件作用前先要么明确一个基本概念,在C语言中调用任意一个函数都必须是先有其定义或声明,随着整个工程越来越庞大实现对所有函数的分类管理变得很有必要,于是我们按照函数间的关联度将所有函数分割为若干的.c文件并把对应的函数声明包含在.h文件中。
调用库文件内容要用#include <XXX.h>
自己定义的库文件要用#include “XXX.h”
具体的.h文件如下
#ifndef _XXX_H //如果没有define _XXX_H,则编译以下内容,知道#endif,这样做是为了防止重复声明下面的void XXX()函数
#define _XXX_H
可以包含其他头文件
宏定义及其他常量定义
void XXX();//函数声明
#endif

#include xxx.h 实际上就是告知编译器在预处理时将xxx.h内的内容复制到当前位置,在某个xxx.c文件中去实现具体的XXX()函数,在这个.c文件中也要声明#include “XXX.h”,这样之后,在其他任意的文件中要用到XXX()函数,只要在头文件中声明#include “XXX.h”,用.h的方式可以模块化程序,同时也可以让代码更精简

三、函数指针和回调函数

1. 函数名、函数指针和指针函数

函数指针:指向函数的指针,指向函数的入口地址
使用函数指针的好处是,可以根据数据的变化调用不同的函数来作为处理方式,常用在回调函数、中断向量表等应用里。一般用法如下

int ( * pfun) (int,int);			//定义一个函数指针pfun
pfun=&max;							//或pfun=max;两种方法都可行,都是把函数指针指向函数入口地址
pfun(1,2);							//或(*pfun)(1,2);两种方法都可行,都是通过函数入口地址调用函数

上述用法中pfun=&max并没有出现报错,给我的感觉是:pfun与max的类型关系类似于int 与int *的关系。然而当使用pfun=max;编译通过给我们的感觉好像函数名就是一个函数指针常量,这有该如何解释呢?

  1. 其实,max的函数名与pfun函数指针都是一样的,即都是函数指针。max函数名是一个函数指针常量,而pfun是一个函数数指针变量,这是它们的关系。
  2. 但函数名调用如果都得如(*pfun)(10);这样,那书写与读起来都是不方便和不习惯的。所以C语言的设计者们才会设计成又可允许pfun(10);这种形式地调用(这样方便多了并与数学中的函数形式一样,不是吗?)。
  3. 为统一起见,pfun函数指针变量也可以pfun(10)的形式来调用。
  4. 赋值时,即可pfun=&max形式,也可pfun=max。
    上述代码的写法,随便你爱怎么着!
    至于指针函数就更好理解了 例int* fun(void); 这里定义了fun函数的返回类型为int型指针,我们称fun为一个指针函数。

2、回调函数

所谓回调函数,就是通过函数指针调用的函数。如果把函数指针作为参数即把一个函数的入口地址传给另一个函数时,当传入的函数指针被用作调用它指向的函数时,称该函数为回调函数。
回调函数的优点是,使调用者和被调用者分离,调用者无需关心具体调用了哪个函数,只需要知道有这样一个函数类型存在。例

void caller(void (* ptr)())
{
	ptr();
}
void fun1();
void fun2();
int main ()
{
	void (* p)();
	p=fun1;
	caller(p);										//调用函数caller不会关心P所指向的函数的具体功能,当P指向的函数地址发生改变,
	p=fun2;											//caller内部就会调用不同函数进行处理
	caller(p);
}

四、使用断言进行安全检测

断言实际上就是一个宏,一个成熟的嵌入式软件工程师常把程序分为Debug版本和release版本,方便进行调试的同时也能保证有稳定的版本可以随时使用。assert 宏仅在Debug版本中起作用,原型定义在 assert.h 中,其作用是如果它的条件返回错误,则终止程序执行。例

#include <assert.h>
void assert( int expression );

assert的作用是先计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
int main( void )
{
       FILE *fp;
    
       fp = fopen( "test.txt", "w" );//以可写的方式打开一个文件,如果不存在就创建一个同名文件
       assert( fp );                           //其作用是如果fp为空,则终止程序执行
       fclose( fp );
    
       fp = fopen( "noexitfile.txt", "r" );//以只读的方式打开一个文件,如果不存在就打开文件失败
       assert( fp );                           //其作用是如果fp为空,则终止程序执行
       fclose( fp );                           
       return 0;
}

不推荐使用assert()的原因是,频繁的调用会极大的影响程序的性能,增加额外的开销。在调试结束后,可以通过在包含#include <assert.h>的语句之前插入 #define NDEBUG 来禁用assert调用,示例代码如下:

#include <stdio.h>
#define NDEBUG
#include <assert.h>
发布了26 篇原创文章 · 获赞 6 · 访问量 3764

猜你喜欢

转载自blog.csdn.net/bojin4564/article/details/105358172