详解为什么include .c文件不常用.doc_第1页
详解为什么include .c文件不常用.doc_第2页
详解为什么include .c文件不常用.doc_第3页
详解为什么include .c文件不常用.doc_第4页
详解为什么include .c文件不常用.doc_第5页
已阅读5页,还剩2页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

今天有人问我: #include能不能include一个(多个.c文件)?偶的回答是:从理论上讲可以,但是不推荐。为什么经常见到include .h文件而不是include .c文件?或者说include是不是就是为包含.h文件设定的语法?这个问题的答案偶不知道,没有见有文档记载、说明这个问题。不过从语法角度讲,include的意思就是从当前位置包含另外一个文件,就象宏替换一样把当前行用另外一个文件的整个内容替换掉。从这点讲,include .c文件是可行的,c编译器完全能够正常处理。但是为什么不常见include .c文件?我想从两个方面可以得到一点解释。一就是,从设计角度上讲,源代码区分为.h和.c文件,是为了接口与实现的分离,实际上两者没什么本质的差别。.h文件提供接口,.c文件提供具体的实现,两者可以一一对应,也可以不一一对应,没有强制要求。一个.c文件做为一个模块的实现,有可能要跟其他的模块打交道,这个时候就需要include其他模块的接口(其他模块的.h文件);而包含其他模块的实现(.c文件)是没有意义的、危险的。二就是从编译角度上来讲,make对同名的.h和.c之间提供隐讳规则的支持,就是说在makefile中不必显式指定一个.c文件依赖于同名的.h文件,就能达到显示指定这一依赖规则的作用。这个规则的副作用就是,如果.c文件中包含了另外的.c文件,除非在Makefile中显示指定这种依赖规则,否则make不会自动添加这种依赖关系。这样,很多时候被包含的.c文件改变了,原本需要重新编译的模块得不到重新编译(除非你手动删除对应的.obj或者执行rebuild),这样的话对工程管理和排错都造成了很大的障碍。所以,我们不应该在项目中include .c文件,这样使用者出于直觉很难想到这里会有问题,增加了排错的难度。前几天偶移植一个国际知名大公司的代码就遇到了这个问题,耗费了半天的时间查看了全部的源码和makefile才发现了这个不常见编译现象。当然,那个公司的代码之所以这么做,是他认为这些代码已经很成熟了,不需要修改和反复重新编译。但它的做法确实对我的调试造成了很大的障碍。谢谢满头大汗的提醒,偶又做了改动:删除线都是写的不对的内容。补充的是:即便是include了.c文件,如果修改Makefile,也能完成其依赖关系。这个帖子放的久了,就不删掉了。 GNU Make Document 中的相关章节 4.12 自动生成依赖在为一个程序编写的makefile文件中,常常需要写许多仅仅是说明一些OBJ文件依靠头文件的规则。例如,如果main.c通过一条#include语句使用defs.h,您需要写入下的规则:main.o: defs.h您需要这条规则让make知道如果defs.h一旦改变必须重新构造main.o。由此您可以明白对于一个较大的程序您需要在makefile文件中写很多这样的规则。而且一旦添加或去掉一条#include语句您必须十分小心地更改makefile文件。为避免这种烦恼,现代C编译器根据原程序中的#include语句可以为您编写这些规则。如果需要使用这种功能,通常可在编译源程序时加入-M开关,例如,下面的命令:cc -M main.c产生如下输出:main.o : main.c defs.h这样您就不必再亲自写这些规则,编译器可以为您完成这些工作。注意,由于在makefile文件中提及构造main.o,因此main.o将永远不会被隐含规则认为是中间文件而进行搜寻,这同时意味着make不会在使用它之后自动删除它;参阅隐含规则链。对于旧版的make程序,通过一个请求命令,如make depend,利用编译器的特点生成依赖是传统的习惯。这些命令将产生一个depend文件,该文件包含所有自动生成的依赖;然后makefile文件可以使用include命令将它们读入(参阅包含其它makefile文件)。在GNU make中,重新构造makefile文件的特点使这个惯例成为了过时的东西您永远不必具体告诉make重新生成依赖,因为GNU make总是重新构造任何过时的makefile文件。参阅Makefile文件的重新生成的过程。我们推荐使用自动生成依赖的习惯是把makefile文件和源程序文件一一对应起来。如,对每一个源程序文件name.c有一名为name.d的makefile文件和它对应,该makefile文件中列出了名为name.o的OBJ文件所依赖的文件。这种方式的优点是仅在源程序文件改变的情况下才有必要重新扫描生成新的依赖。这里有一个根据C语言源程序name.c生成名为name.d依赖文件的格式规则:%.d: %.c set -e; $(CC) -M $(CPPFLAGS) $ $; -s $ | rm -f $关于定义格式规则的信息参阅定义与重新定义格式规则。-e开关是告诉shell如果$(CC)命令运行失败(非零状态退出)立即退出。正常情况下,shell退出时带有最后一个命令在管道中的状态(sed),因此make不能注意到编译器产生的非零状态。对于GNU C编译器您可以使用-MM开关代替-M,这是省略了有关系统头文件的依赖。详细内容参阅GNU CC使用手册中控制预处理选项。命令Sed的作用是翻译(例如):main.o : main.c defs.h到:main.o main.d : main.c defs.h这使每一个.d文件和与之对应的.o文件依靠相同的源程序文件和头文件,据此,Make可以知道如果任一个源程序文件和头文件发生变化,则必须重新构造依赖文件。一旦您定义了重新构造.d文件的规则,您可以使用使用include命令直接将它们读入,(参阅包含其它makefile文件),例如:sources = foo.c bar.cinclude $(sources:.c=.d)(这个例子中使用一个代替变量参照从源程序文件列表foo.c bar.c翻译到依赖文件列表foo.d bar.d。详细内容参阅替换引用。)所以,.d的makefile文件和其它makefile文件一样,即使没用您的任何进一步的指令,make同样会在必要的时候重新构建它们。参阅Makefile文件的重新生成过程。-乾坤一笑 写于2005年7月26日转载请标明出处和原文链接-next-嗯。GNU Make手册的开头就说出了很多人不知道的知识它不仅仅用于编译的:p GNU Make Document 中的相关章节 GNU Make符合IEEE Standard 1003.2-1992 (POSIX.2) 6.2章节的规定。因为C语言程序更具有代表性,所以我们的例子基于C语言程序,但Make并不是仅仅能够处理C语言程序,它可以处理那些编译器能够在Shell命令下运行的的各种语言的程序。事实上,GNU Make不仅仅限于程序,它可以适用于任何如果一些文件变化导致另外一些文件必须更新的任务。如果要使用Make,必须先写一个称为Makefile的文件,该文件描述程序中各个文件之间的相互关系,并且提供每一个文件的更新命令。在一个程序中,可执行程序文件的更新依靠OBJ文件,而OBJ文件是由源文件编译得来的。一旦合适的Makefile文件存在,每次更改一些源文件,在shell命令下简单的键入:make就能执行所有的必要的重新编译任务。Make程序根据Makefile文件中的数据和每个文件更改的时间戳决定哪些文件需要更新。对于这些需要更新的文件,Make基于Makefile文件发布命令进行更新,进行更新的方式由提供的命令行参数控制。-next-这属于滥用#include.为何要分为头文件和源文件?本来就是为了传递如下信息:类型定义外部函数原型外部变量宏这部分不产生任何实际代码的东西。c各文件之间的代码是通过#include来引入的吗?这属于连接器的工作!怀疑使用这个的人,也许是因为源文件的代码太长了,就滥用#include,将源代码分到几个文件上。我估计将实现这种招数的办法是将源代码划分为一个主多个从的关系,主的引入所有从文件。他们的内容有如下规定:主文件,包括所有外部连接的代码(公共)从文件,所有元素具备内部连接(私有)对于客户端来说,只有主文件才是他们真正去要连接的。而因为从文件都是内部连接,相关的.obj将毫无疑义的被丢弃,因为主文件有着一模一样的拷贝。当然更蹩脚的办法是将这些#include了的源文件排除出项目定义文件。#include和include的区别1楼、包含头文件,只是用头文件里面的内容,在本文件中声明一下,它并不是本文件的一部分包含c文件,是把c文件整个内容当作本文件的一部分了,XX.c你的内容加入了本文件2楼、#include是标准的引入方式也是常用的#inlucde可能让程序可读性变差3楼、在预编译时,#include指令将包含的头文件的内容结合预处理指令扩展到源文件中,在头文件中最好只包含声明(不是必须,不要包含头文件),在同名(方便管理)的源文件中的一些声明(需要包含头文件,生成目标文件时需要有语法检查),在main.c中包含.h 即可编程。头文件应该放些什么?1,宏定义 结构体,联合体,枚举的声明 typedef声明 外部函数声明 全局变量声明 2,当声明或宏定义需要在多个文件中共享时,尤其需要把他们加入到头文件。3,永远不要把外部函数原型(即外部函数声明)放到.c文件中。4,如果一个宏或声明为一个.c文件按私有,最好放在.c文件中。4楼、从C编译器角度看,.h和.c皆是浮云。换句话说,就是.h和.c没啥必然联系。.h中一般放的是同名.c文件中定义的变量、数组、函数的声明,需要让.c外部使用的声明。这个声明只是让需要用这些声明的地方方便引用。因为 #include xx.h 这个宏其实际意思就是把当前这一行删掉,把 xx.h 中的内容原封不动的插入在当前行的位置。由于想写这些函数声明的地方非常多(每一个调用 xx.c 中函数的地方,都要在使用前声明一下子),所以用 #include xx.h 这个宏就简化了许多行代码让预处理器自己替换好了。也就是说,xx.h 其实只是让需要写 xx.c 中函数声明的地方调用(可以少写几行字),至于 include 这个 .h 文件是谁,是 .h 还是 .c,还是与这个 .h 同名的 .c,都没有任何必然关系5楼、xx.h通常只包含声明、宏、typedef类型同义词、函数声明、模板等等,一般称为接口xx.c包含的是源代码,一般成为实现。通常是不使用包含源代码的方式的,源代码文件直接加入工程就行了。包含源代码的方式用得较多的情况是模板的实现。6楼、常用的工程管理办法是将所有的.c文件都编译成.o文件,然后把它们合并连接成程序。如果使用#include 这样的方式,那么xx.c里面的代码会被编译两次,连接时会导致符号重复而无法连接。事实上你#include 也是可以的,只要把xx.txt里写的是c语言代码。#include xx.X 如果你不只包含了.h文件,那说明你的工程很不清晰。7楼、#include 可行但不国际化最近看数据结构,才发现还可以#include file.cpp,小诧异了一把。8楼、1。 对于#include这个语句来说,include什么文件到当前文件都是程序员的事,没有问题。一般来说.h文件是放声明的,.c文件是放定义的,也就是实现的。2。 如果你include的c文件中实现了函数foo(),或者定义了变量int i,并且这个c文件被你不小心在同一个项目的另一个文件中也include了,那么这就会出现重复定义的错误。3。 include源代码c文件是没有意义的。因为如果当前c文件中要用到另一个c文件的变量或者函数,他只需当前c文件中用extern声明一下要使用的函数或变量就好了.4. 虽然后缀名写成什么并没有本质的对错问题,但是编译器一般是有假设的。对于编译器来说,一个.c文件是一个translation unit,而.h文件不是。所以从这个角度来说,后缀名就不是一个随便的事情了。9楼、#includexx.c算什么当年我一个朋友特别喜欢#includexx.fuck10楼、没有区别我还看到过char a =#include xx.txt;这是良好的代码设计风格,非常精巧的模块化11楼、#include 完全等价于把那个文件的内容复制到本文件里12楼、#include *.h是标准用法#include *.c应该禁止使用,因为编译器会把你包含的c文件也编译一遍并试图链接,从而导致符号重定义问题#include *.cpp只应该用于模板类、模板函数的实现文件,如果你的实现放在cpp中13楼、对#include预处理命令来说#include 与#include 是没有区别的。但从其它角度看就有区别了:1)包含文件名用括起来,通常编译器仅从系统的include目录中找文件,而一般.c文件是程序员自己写的通常在工程目录中,因此#include 会提示找不到文件。2)一般情况下,.h文件中仅有声明,而没有定义,但在.c文件中通常会有定义。这样如果工程中有多个文件包含.c文件,就会产生连接性错误。如:C/C+ code /xx.c int xx() /*.*/ /1.c #include xx.c /其它代码. /2.c #inclu

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论