c语言中的h文件与c文件的理解、编写及使用

来源:互联网 发布:美西自驾游攻略知乎 编辑:程序博客网 时间:2024/06/05 18:33

【by:mallon】

    在c语言编程中,我们会将要实现的应用写成.c文件:系统级的应用,我们会编写一个含有main函数的.c文件,来实现系统级的函数调用已达成我们所要的功能;具体的各个功能模块,我们习惯于写成单独的.c文件,然后在主程序main函数之前会include所需模块的.h头文件。这样的软件组织结构使程序结构清晰,便于各个模块的调试,提高了工作效率。先提出我最开始接触时的一些疑惑吧。

疑问

    .c和.h文件中都有哪些内容?程序在编译连接的过程中,它们是怎么调用的?如何写c文件的头文件(.h文件)?

编译过程介绍:

   首先,需要了解一下编译器的工作过程:一个程序的编译通常有包含以下几个阶段:预处理阶段、词法和语法分析阶段、编译阶段和连接阶段。当词法和语法分析无误后,编译生成目标文件(如obj文件), 之后连接器以目标文件为对象,对各段代码中的函数和变量进行绝对地址定位,生成可执行的文件(如exe文件)。

    在编预处理阶段编译器开始读取C文件,当读到包含其它的都文件时,就会在所有路径中搜索相应的头文件,找到后处理.h文件中的一些声明,如果没有重复的声明,则编译器对所有.h文件处理结果会增加到当前的c文件中,生成一个新的c文件。编译阶段对这个新的c文件的函数和变量分配空间,并编译生成目标文件,每一个c文件都会生成一个目标文件。在连接阶段,连接器对各个目标文件重新定位,生成可执行文件。

c文件与h文件关系:

    我们当然也可以在C文件中进行函数声明,变量声明,结构体声明,但为何一定要分成头文件与C文件呢?又为何一般都在头件中进行函数,变量声明,宏声明,结构体声明呢?而在C文件中去进行变量定义,函数实现呢?主要原因如下:

1.如果在头文件中实现一个函数体,那么如果在多个C文件中引用它,而且又同时编译多个C文件,将其生成的目标文件连接成一个可执行文件,在每个引用此头文件的C文件所生成的目标文件中,都有一份这个函数的代码,如果这段函数又没有定义成局部函数,那么在连接时,就会发现多个相同的函数,就会报错
2.如果在头文件中定义全局变量,并且将此全局变量赋初值,那么在多个引用此头文件的C文件中同样存在相同变量名的拷贝,关键是此变量被赋了初值,所以编译器就会将此变量放入DATA段,最终在连接阶段,会在DATA段中存在多个相同的变量,它无法将这些变量统一成一个变量,也就是仅为此变量分配一个空间,而不是多份空间,假定这个变量在头文件没有赋初值,编译器就会将之放入BSS段,连接器会对BSS段的多个同名变量仅分配一个存储空间
3.如果在C文件中声明宏,结构体,函数等,那么我要在另一个C文件中引用相应的宏,结构体,就必须再做一次重复的工作,如果我改了一个C文件中的一个声明,那么又忘了改其它C文件中的声明,这不就出了大问题了,程序的逻辑就变成了你不可想象的了,如果把这些公共的东东放在一个头文件中,想用它的C文件就只需要引用一个就OK了!!!这样岂不方便,要改某个声明的时候,只需要动一下头文件就行了
4.在头文件中声明结构体,函数等,当你需要将你的代码封装成一个库,让别人来用你的代码,你又不想公布源码,那么人家如何利用你的库呢?也就是如何利用你的库中的各个函数呢??一种方法是公布源码,别人想怎么用就怎么用,另一种是提供头文件,别人从头文件中看你的函数原型,这样人家才知道如何调用你写的函数,就如同你调用printf函数一样,里面的参数是怎样的??你是怎么知道的??还不是看人家的头文件中的相关声明啊!!!当然这些东东都成了C标准,就算不看人家的头文件,你一样可以知道怎么使用.

////////////////////////////////////////////////////////////////////////

编写h文件实例说明  

   例如在main.c的文件中#include“uart.h”后,程序在编译的过程中,会首先将的寻找并调用uart.h文件,生成目标文件,在连接阶段连接器将由main.c和uart.c生成的两个目标文件分配地址,即明确程序入口地址,相应函数之间的调用关系,生成了实现uart模块功能的应用程序。

   以下程序不用细看,我们只需要知道该c文件是一些实现具体功能的函数组成的就行。该c文件也include了一些头文件,如编译过程介绍的那样,这写文件是编译该c文件所需的。

UART的C文件

#include "system.h"
#include "altera_avalon_pio_regs.h"
#include "alt_types.h"

#include "sys/alt_stdio.h"   
#include <sys/alt_irq.h>   
#include <stdio.h>  
#include <string.h>  
#include "altera_avalon_uart_regs.h"   

//UART发送一个字节子程序
void Uart_send(unsigned char data)
{
alt_u16 status;
status=IORD_ALTERA_AVALON_UART_STATUS(UART_BASE);
while(!(status&0x0040))//等待发送完成
status=IORD_ALTERA_AVALON_UART_STATUS(UART_BASE);
IOWR_ALTERA_AVALON_UART_TXDATA(UART_BASE,data);
}
//UART发送多个字节子程序
void Uart_send_n(unsigned char *ptr,unsigned char n)
{
for(;n>0;n--)
{
Uart_send(*ptr);
ptr++;
}
}
//UART接收子程序
int Uart_receive(void)
{
alt_u16 status;
int temp;
status=IORD_ALTERA_AVALON_UART_STATUS(UART_BASE);
while(!(status&0x0080))//等待发送完成
status=IORD_ALTERA_AVALON_UART_STATUS(UART_BASE);
temp=IORD_ALTERA_AVALON_UART_RXDATA(UART_BASE);
return temp;
}
//串口接收中断服务程序
void Uart_ISR(void * context,alt_u32 id)
{
unsigned char temp;
unsigned char leddata;
temp=IORD_ALTERA_AVALON_UART_RXDATA(UART_BASE);
leddata=temp;
Uart_send(temp);

IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,leddata);
//printf("temep=%x",temp);
}
//串口中断初始化
void Uart_init()
{
IOWR_ALTERA_AVALON_UART_CONTROL(UART_BASE, 0x80);//接收中断使能
IOWR_ALTERA_AVALON_UART_STATUS(UART_BASE, 0x0);//清状态标志
IOWR_ALTERA_AVALON_UART_RXDATA(UART_BASE, 0x0);//清接收寄存器
alt_irq_register(UART_IRQ,0,Uart_ISR);//中断注册,此处编译总出现警告,
//还请高手能指点。warning: implicit declaration of function
//`alt_irq_register' test3 uart_zx.h,加上中断的头文件#include <sys/alt_irq.h>
}


接着写h文件,注意文件名要与c文件名相同。

UART的h文件

#ifndef UART_H_
#define UART_H_
     void Uart_send(unsigned char data);
     void Uart_send_n(unsigned char *ptr,unsigned char n);
     int Uart_receive(void);
     void Uart_ISR(void * context,alt_u32 id);
     void Uart_init();
     char leddata;

#endif /*UART_H_*/

红色部分是定义头文件的格式

黑色部分是在UART同名的c文件中的函数和变量的声明。

///////////////////////////////////////////////////////////////////////

总结:我们写好一个系统模块的应用程序,想将它分为c文件和h文件,c文件可以按正常的步骤写,写完之后按照h文件的写作格式,在h文件中对c文件的变量和函数进行声明就行。这样我们在含有main函数的c文件中通过#include该头文件,就可以调用该模块的函数了。我们设备的驱动程序也可以这样添加。


工作几年竟让把大学时学的C忘了个七七八八,现用现查。。。。。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 电脑显示器闪屏然后黑屏怎么办 枪火游侠闪退怎么办 欧卡2气压过低怎么办 微信安装包己损坏怎么办 qq超市金币累计满了怎么办 我该怎么办?欠了那么多钱? 枪神王座被检测怎么办 酷派大神x7刷机出1004怎么办 水鬼捞锤塌方了怎么办 请事假领导不批怎么办 要请假领导不批怎么办 有急事请假不批怎么办 员工要请假不批怎么办 普法知识竞赛要重新参与怎么办 我被当兵的打怎么办 头发没了一小块怎么办 改革怎么看我该怎么办 笔记本电脑卡死了怎么办关不了机 电脑卡死了怎么办关不了机 火车上别人占座怎么办 火车上遇到占座怎么办 青少年体力差容易疲劳怎么办 四年级的孩子作业拖拉怎么办 四年级孩子不写作业怎么办 四年级孩子不爱写作业怎么办 四年级的孩子写作业慢怎么办 四年级孩子不想写作业怎么办 四年级孩子写作业特别慢怎么办 6岁儿童睡眠少怎么办 四岁儿童睡眠少怎么办 因睡眠不足第二天没有精神怎么办 睡时间久了头疼怎么办 睡不踏实老醒怎么办 运动过后大腿肌肉酸痛怎么办 牛奶喝多了想吐怎么办 运动过度后吐了怎么办 喝酒后反胃想吐怎么办 拔牙后反胃想吐怎么办 健身完恶心想吐怎么办 锻炼后头晕想吐怎么办 高三学生睡眠不好怎么办