




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、c语言头文件的作用最近在工作当中遇到了一点小问题,关于c语言头文件的应用问题,主要还是关于全局变量的定义和声明问题.学习c语言已经有好几年了,工作使用也近半年了,但是对于这部分的东西的确还没有深入的思考过.概念上还是比较模糊的,只是之前的使用大多比较简单,并没有牵涉到太复杂的工程,所以定义和声明还是比较简单而明了了的.但是最近的大工程让我在这方面吃到了一点点苦头,虽然看了别人的代码能够很快的改正,但是这些改正背后的原因却不知道.我想大多数喜欢c语言的程序员应该是和我一样的,总喜欢去追究程序问题背后的底层原因,而这也恰恰是我喜欢c语言的最根本的原因.今天看过janders老兄在csdn上的一篇文
2、章后,理解的确加深了很多,而且还学到一些以前不怎么知道的知识.现将文章转载过来,并对文章当中的一些拼写错误做了简单的纠正,同时对文字及布局做了少许修改.(如果想看原文的,请参考本文底部的链接.)c语言中的.h文件和我认识由来已久,其使用方法虽不十分复杂,但我却是经过了几个月的“不懂”时期,几年的“一知半解”时期才逐渐认识清楚他的本来面目。揪其原因,我的驽钝和好学而不求甚解固然是原因之一,但另外还有其他原因。原因一:对于较小的项目,其作用不易被充分开发,换句话说就是即使不知道他的详细使用方法,项目照样进行,程序在计算机上照样跑。原因二:现在的各种c语言书籍都是只对c语言的语法进行详细的不能再详细
3、的说明,但对于整个程序的文件组织构架却只字不提,找了好几本比较著名的c语言著作,却没有一个把.h文件的用法写的比较透彻的。下面我就斗胆提笔,来按照我对.h的认识思路,向大家介绍一下。让我们的思绪乘着时间机器回到大学一年级。c原来老师正在讲台上讲着我们的第一个c语言程序: hello world!文件名 first.cmain() printf(“hello world!”); 例程-1看看上面的程序,没有.h文件。是的,就是没有,世界上的万物都是经历从没有到有的过程的,我们对.h的认识,我想也需要从这个步骤开始。这时确实不需要.h文件,因为这个程序太简单了,根本就不需要。那么如何才能需要呢?让
4、我们把这个程序变得稍微复杂些,请看下面这个,文件名 first.cprintstr() printf(“hello world!”);main()printstr(); 例程-2还是没有, 那就让我们把这个程序再稍微改动一下.文件名 first.cmain()printstr();printstr() printf(“hello world!”); 例程-3等等,不就是改变了个顺序嘛, 但结果确是十分不同的. 让我们编译一下例程-2和例程-3,你会发现例程-3是编译不过的.这时需要我们来认识一下另一个c语言中的概念:作用域. 我们在这里只讲述与.h文件相关的顶层作用域, 顶层作用域就是从声明点
5、延伸到源程序文本结束, 就printstr()这个函数来说,他没有单独的声明,只有定义,那么就从他定义的行开始,到first.c文件结束, 也就是说,在在例程-2的main()函数的引用点上,已经是他的作用域. 例程-3的main()函数的引用点上,还不是他的作用域,所以会编译出错. 这种情况怎么办呢? 有两种方法 ,一个就是让我们回到例程-2, 顺序对我们来说没什么, 谁先谁后不一样呢,只要能编译通过,程序能运行, 就让main()文件总是放到最后吧. 那就让我们来看另一个例程,让我们看看这个方法是不是在任何时候都会起作用.文件名 first.c play2() .play1();. pla
6、y1() .play2(); main()play1();例程-4也许大部分都会看出来了,这就是经常用到的一种算法, 函数嵌套, 那么让我们看看, play1和play2这两个函数哪个放到前面呢? 这时就需要我们来使用第二种方法,使用声明. 文件名 first.cplay1();play2();play2().play1();. play1() .play2(); main()play1();例程-4经历了我的半天的唠叨, 加上四个例程的说明,我们终于开始了用量变引起的质变, 这篇文章的主题.h文件快要出现了。一个大型的软件项目,可能有几千个,上万个play, 而不只是play1,play2这
7、么简单, 这样就可能有n个类似 play1(); play2(); 这样的声明, 这个时候就需要我们想办法把这样的play1(); play2(); 也另行管理, 而不是把他放在.c文件中, 于是.h文件出现了.文件名 first.hplay1();play2();文件名 first.c#include “first.h”play2().play1();. play1(); . play2(); main()play1();例程-4各位有可能会说,这位janders大虾也太罗嗦了,上面这些我也知道, 你还讲了这么半天, 请原谅, 如果说上面的内容80%的人都知道的话,那么我保证,下面的内容,8
8、0%的人都不完全知道. 而且这也是我讲述一件事的一贯作风,我总是想把一个东西说明白,让那些刚刚接触c的人也一样明白.上面是.h文件的最基本的功能,那么.h文件还有什么别的功能呢? 让我来描述一下我手头的一个项目吧.这个项目已经做了有10年以上了,具体多少年我们部门的人谁都说不太准确,况且时间并不是最主要的,不再详查了。是一个通讯设备的前台软件, 源文件大小共 51.6m, 大小共1601个文件, 编译后大约10m, 其庞大可想而知,在这里充斥着错综复杂的调用关系,如在second.c中还有一个函数需要调用first.c文件中的play1函数, 如何实现呢? sencond.h 文件play1(
9、);sencond.c文件*().play();.例程-5在second.h文件内声明play1函数,怎么能调用到first.c文件中的哪个play1函数中呢? 是不是搞错了,没有搞错, 这里涉及到c语言的另一个特性:存储类说明符.c语言的存储类说明符有以下几个, 我来列表说明一下 说明符用 法auto只在块内变量声明中被允许, 表示变量具有本地生存期.extern出现在顶层或块的外部变量函数与变量声明中,表示声明的对象具有静态生存期, 连接程序知道其名字.static可以放在函数与变量声明中,在函数定义时,只用于指定函数名,而不将函数导出到链接程序,在函数声明中,表示其后边会有定义声明的函数
10、,存储类型static.在数据声明中,总是表示定义的声明不导出到连接程序.无疑, 在例程-5中的second.h和first.h中,需要我们用extern标志符来修饰play1函数的声明,这样,play1()函数就可以被导出到连接程序, 也就是实现了无论在first.c文件中调用,还是在second.c文件中调用,连接程序都会很聪明的按照我们的意愿,把他连接到first.c文件中的play1函数的定义上去, 而不必我们在second.c文件中也要再写一个一样的play1函数.但随之有一个小问题, 在例程-5中,我们并没有用extern标志符来修饰play1啊, 这里涉及到另一个问题, c语言中
11、有默认的存储类标志符. c99中规定, 所有顶层的默认存储类标志符都是extern . 原来如此啊,哈哈.回想一下例程-4, 也是好险, 我们在无知的情况下, 竟然也误打误撞,用到了extern修饰符, 否则在first.h中声明的play1函数如果不被连接程序导出,那么我们在在play2()中调用他时, 是找不到其实际定义位置的 .那么我们如何来区分哪个头文件中的声明在其对应的.c文件中有定义,而哪个又没有呢?这也许不是必须的,因为无论在哪个文件中定义,聪明的连接程序都会义无返顾的帮我们找到,并导出到连接程序, 但我觉得他确实必要的. 因为我们需要知道这个函数的具体内容是什么,有什么功能,
12、有了新需求后我也许要修改他,我需要在短时间内能找到这个函数的定义, 那么我来介绍一下在c语言中一个人为的规范:在.h文件中声明的函数,如果在其对应的.c文件中有定义,那么我们在声明这个函数时,不使用extern修饰符, 如果反之,则必须显示使用extern修饰符.这样,在c语言的.h文件中,我们会看到两种类型的函数声明. 带extern的,还不带extern的, 简单明了,一个是引用外部函数,一个是自己生命并定义的函数.最终如下:sencond.h 文件extern play1();上面洋洋洒洒写了那么多都是针对函数的,而实际上.h文件却不是为函数所御用的. 打开我们项目的一个.h文件我们发现
13、除了函数外,还有其他的东西, 那就是全局变量.在大型项目中,对全局变量的使用不可避免, 比如,在first.c中需要使用一个全局变量g_test, 那么我们可以在first.h中,定义 tpye g_test. 与对函数的使用类似, 在second.c中我们的开发人员发现他也需要使用这个全局变量, 而且要与first.c中一样的那个, 如何处理? 对,我们可以仿照函数中的处理方法, 在second.h中再次声明tpye g_test, 根据extern的用法,以及c语言中默认的存储类型, 在两个头文件中声明的tpye g_test,其实其存储类型都是extern, 也就是说不必我们操心, 连接
14、程序会帮助我们处理一切. 但我们又如何区分全局变量哪个是定义声明,哪个是引用声明呢?这个比函数要复杂一些, 一般在c语言中有如下几种模型来区分:1、初始化语句模型顶层声明中,存在初始化语句是,表示这个声明是定义声明,其他声明是引用声明。c语言的所有文件之中,只能有一个定义声明。按照这个模型,我们可以在first.h中定义如下tpye g_test=1;那么就确定在first中的是定义声明,在其他的所有声明都是引用声明。2、省略存储类型说明在这个模型中,所有引用声明要显示的包括存储类extern,而每个外部变量的唯一定义声明中省略存储类说明符。这个与我们对函数的处理方法类似,不再举例说明。 这里
15、还有一个需要说明,本来与本文并不十分相关,但前一段有个朋友遇到此问题,相信很多人都会遇到,那就是数组全局变量。他遇到的问题如下:在声明定义时,定义数组如下:int g_glob100;在另一个文件中引用声明如下:int * g_glob;在vc中,是可以编译通过的,这种情况大家都比较模糊并且需要注意,数组与指针类似,但并不等于说对数组的声明起变量就是指针。上面所说的的程序在运行时发现了问题,在引用声明的那个文件中,使用这个指针时总是提示内存访问错误,原来我们的连接程序并不把指针与数组等同,连接时,也不把他们当做同一个定义,而是认为是不相关的两个定义,当然会出现错误。正确的使用方法是在引用声明中
16、声明如下:int g_glob100;并且最好再加上一个extern,更加明了。extern int g_glob100; 另外需要说明的是,在引用声明中由于不需要涉及到内存分配,可以简化如下,这样在需要对全局变量的长度进行修改时,不用把所有的引用声明也全部修改了。extern int g_glob; c语言是现今为止在底层核心编程中,使用最广泛的语言,以前是,以后也不会有太大改变,虽然现在java,.net等语言和工具对c有了一定冲击,但我们看到在计算机最为核心的地方,其他语言是无论如何也代替不了的,而这个领域也正是我们对计算机痴迷的程序员所向往的。好了,看完文章,对与c语言头文件的作用应该
17、有了跟多的理解吧,如果这些你原本都知道了,那么仅当是温习一下而已,如果原本不知道,那么恭喜你,现在又学到一些技巧和知识.对于全局变量的定义和声明,其实还有另外一个解决的方法,聪明的你可能早已经猜到了:),没错,就是用宏定义的技巧实现.比如a.h文件当中有: #ifdef aaaint i=0;#elseint i;#endif那么,在a.c文件当中,有如下语句:.#define aaa#include a.h.而对于其他的任何包含a.h文件的头文件或者.c源文件,只需要直接包含a.h就行了.#include a.h.这样就可以达到在a.c文件当中定义变量一次,而在其他的文件当中声明该变量的目的.当然了,你完全可以根据自己的需要来决定在哪个需要包含a.h的文件当中定义宏aaa,但是我要说的是在同一个工程的不同的需要包含a.h的文件当中,你只能定义aaa一次,否则在连接这些目标文件时会出现重复定义的错误,即使你的单独目标文件编译没有任何的问题.当然,这里说的仅仅是对全局变量的声明技巧,强烈的推介大家在头文件中使用宏定义实现对整个头文件的防止重复包含,当然了,这
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 江西省上饶市2024-2025学年高一上学期1月期末英语试题【含答案】
- 江苏省常州市2024-2025学年高三(上)期末生物试卷(含解析)
- 青贮池施工方案
- 排涝水系改造施工方案
- 生物观察池施工方案
- co2加氢制甲醇总反应
- 4年级数学手抄报内容
- 地平关环机理
- 青海墙面防水施工方案
- 2025年广西农业职业技术大学单招职业技能测试题库汇编
- 2025口腔科年度工作计划
- 商业办公楼网络改造施工方案
- 2024年中国主题公园竞争力评价报告-中国主题公园研究院
- 2023年湖北省生态环保有限公司招聘考试真题
- 化疗药物外渗的预防及处理-2
- DB35T 1933-2020 熔融沉积3D打印品几何精度评价规范
- 《大气污染物控制工程》-挥发性有机物污染控制
- 2024-2030年冷冻面团产品行业市场现状供需分析及投资评估规划分析研究报告
- LED基础知识题库100道及答案(完整版)
- 新版高中物理必做实验目录及器材-(电子版)
- 涉密项目保密工作方案
评论
0/150
提交评论