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

【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忘了个七七八八,现用现查。。。。。

### 回答1: IAR Embedded Workbench是一款集成开发环境,可以用于嵌入式系统应用的开发。在IAR Embedded Workbench建立.c和.h文件十分简单。 首先,在IAR Embedded Workbench创建一个新的项目。接下来,在项目创建一个新的源文件,可以选择“Add New Item”或者右键单击“Source Files”文件夹,并选择“Add File to Group”。在弹出的新文件窗口选择“C-file (.c)”或者“Header File (.h)”文件类型。输入文件名并点击“OK”即可创建文件。 如果要在项目添加已有的.c或者.h文件,可以右键单击所在文件夹,选择“Add Existing Item”,然后选择对应的文件。 在IAR Embedded Workbench,可以通过“Project Explorer”窗口来管理项目文件。在窗口可以看到所有的.c和.h文件,在需要的位置上右键单击即可进行新增或者添加文件的操作。 ### 回答2: IAR是一个集成的开发环境,可以用于ARM、AVR和其他微控制器的开发。要建立.c和.h文件,需要执行以下步骤: 1. 在IAR创建一个新的工程,选择适合的芯片和编译器。 2. 在工程菜单选择“新建”,然后在弹出菜单选择“C源文件”或“头文件”。 3. 输入文件名并选择目标文件夹。需要注意的是,头文件应该以.h为后缀名,C文件应该以.c为后缀名。 4. 在文件编辑器输入代码并保存文件。 如果需要在多个源文件共享相同的变量和函数,可以通过头文件来实现。头文件可以包含变量和函数的声明,例如,在.h文件声明变量和函数: #ifndef __MYHEADER_H__ #define __MYHEADER_H__ /* 声明函数 */ void my_function(void); /* 声明变量 */ extern int my_variable; #endif /* __MYHEADER_H__ */ 然后在.c文件定义变量和函数: #include "myheader.h" /* 定义变量 */ int my_variable = 0; /* 定义函数 */ void my_function(void) { // do something } 这样,其他源文件就可以包含这个头文件,来使用这个变量和函数了。 ### 回答3: 编写C和H文件是IAR的基本操作之一。如果您想在IAR编写C代码和头文件,请按照以下步骤操作: 1. 首先,打开IAR Embedded Workbench并创建一个新的工程。这可以通过从菜单栏选择“File”>“New”>“Project”来完成。 2. 在窗口选择您想要的设备和平台,并为新项目选择一个名称和目录。 3. 选择“Create file”选项,并选择“C File”或“Header File”作为您要创建的文件类型。 4. 在“Filename”输入您想要为文件命名的名称,并确保将其保存在正确的文件。 5. 按下“确定”键来创建您的文件。 6. 成功创建C文件和头文件之后,您可以在IAR编辑它们并将它们添加到您的项目。 在IAR编写C代码和头文件并不困难。只需按照以上步骤操作即可轻松创建和编辑文件。请注意,确保将所有文件保存在正确的位置,并始终使用适当的文件命名约定,以确保能够轻松找到和管理您的代码库。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值