h和.cpp的区别
.c和.h文件的区别
.c和.h文件的区别一个简单的问题:.c和.h文件的区别学了几个月的C语言,反而觉得越来越不懂了。
同样是子程序,可以定义在.c文件中,也可以定义在.h文件中,那这两个文件到底在用法上有什么区别呢?2楼:子程序不要定义在.h中。
函数定义要放在.c中,而.h只做声明.否则多引用几次,就会发生函数重复定义的错误。
3楼:.h只做声明,编译后不产生代码4楼:这样做目的是为了实现软件的模块化使软件结构清晰,而且也便于别人使用你写的程序纯粹用 C 语言语法的角度,你当然可以在 .h 中放任何东西,因为#include 完全等价于把 .h 文件 Ctrl-C Ctrl-V 到 .c 中.h 中应该都是一些宏定义和变量、函数声明,告诉别人你的程序“能干什么、该怎么用”.c 中是所有变量和函数的定义,告诉计算机你的程序“该怎么实现”5楼:当然,如果一个 .h 被多个 .c 包含而且 .h 中有对象(变量或函数)的定义,就会发生重复定义的错误了声明可以无穷多次,定义只能一次6楼:一般来说,一个C文件应该是一个模块如果你的程序仅仅有一个模块(仅仅一个C文件),就可以不用建立H文件了。
否则你的模块肯定不是独立的,你的模块里面的实现要被别的模块调用。
这个时候你最好生成一个头文件(H文件),在头文件里面可以声明你的那些函数是公共的。
当别的模块包含你的头文件后,就可以使用你的公共声明了。
7楼:一个C对应一个H,这样管理起来方便比如你有一个"feed_dog.c",那么就再添加一个"feed_dog.h":#ifndef _feed_dog_h#define _feed_dog_hextern void feed_dog(void);#endif其实在H文件里写函数也无所谓,只是不符合习惯而已。
只要按照以上的格式写,一个H文件添加多少次都无所谓,呵呵8楼:只是一种约定在编译器里面,.c和.h是没有区别的,.c和.h如何使用完全取决于程序员,不过为了你的程序以后还能看懂而且别人也能看懂,请遵守普遍的约定,这些约定前面的大虾们已经讲了很多了.这个就象汽车在马路上要靠右行使一样,是人为约定,汽车(编译器)本身并不知道自己是在靠左还是靠右行使.如果你喜欢,还可以用任意后缀命名源文件和头文件,但这样干可能会导致集成编译和调试环境罢工,你只好自己写makefile文件了.9楼:非常感谢各位大侠,不过我现在越来越糊涂了1,当一个函数要经常使用(比如有十几个C文件使用它)时,一般我都放在H文件里,并在前面加上__inline.对于__inline函数,很多C文件都可以INCLUDE这个H文件,但是它好象只能被一个H文件INCLUDE,如果有两个H文件INCLUDE它,就会出现编译错误。
一个工程有.cpp,.h等很多文件,他们是怎么连接在一起的?
一个工程有.cpp,.h等很多文件,他们是怎么连接在一起的?可以有多个CPP,但CPP的名字不能相同,因为编译的OBJ的文件是以CPP为单位。
不同CPP文件的函数可以通过声明的方式使用,通常声明放在H文件里,而想引用其它CPP文件的变量可以使用extern 这个也通常放在H文件通过#include的方式加载可以有多个.cpp,甚至是多个.cpp,.c混合都是没有问题的,多个cpp时最好使用预编译头,也是就建立console工程的时候不选空工程,简单例程或HELLO WORLD程序,自己添加cpp代码文件时,确保在文件的头部写上#include 就可以了------解决方案--------------------------------------------------------每个.cpp文件作为一个编译单元,被编译成一个目标文件(.obj),它用目标语言来描述.cpp的内容。
然后,用一个链接器将所有的目标文件链接起来,形成一个.exe文件。
换句话说,在第一阶段,每个.cpp都是独立编译的,互不干涉(当然可以使用公用的.h文件)。
在最后链接时才归并在一起。
所有在.exe中的实际地址,都是在链接时生成的。
比如说,a.cpp中调用了一个函数fun(),b.cpp中实现了函数fun()。
那么a.cpp编译成a.o时,会建立一个地址表,一种有一项 a_fun_address,用于调用函数fun()时的跳转地址。
但是,这个地址在a.o中是不知道的,因此它声明需要这个地址,然后在调用fun()初写:call [a_fun_address] // 此处是调用fun的伪目标语言而b.o中则从它的b_fun_address处开始写fun的实现。
如:b_fun_address:XXXX // 此处是实现fun的伪目标语言然后在链接时,链接器将fun的实现(b_fun_address开始的目标代码)确定到某个地址上,并将这个地址回写到a_fun_address上。
C++初学者建立.H头文件和.CPP文件
C++初学者建⽴.H头⽂件和.CPP⽂件⾸先要明⽩这些⽂件时什么⽂件,再⽤编译器,例如:VC6.0,Dev C++等编译环境中运⾏,你可以打开VC6.0界⾯,⼀般⽤得较多的是Win32控制台应⽤程序(源程序,扩展名.cpp),步骤是:1,建⽴⼀个⼯程,“⽂件”——“新建”,出现下⾯界⾯:选择“Win32Console Application”(控制台应⽤程序,左边倒数第三个),命名⼯程名称,选择保存位置,点击“确定”,进⼊下⼀步,看到如下提⽰界⾯:建⽴⼀个空⼯程,对应其他需要的你⼀可以建⽴别的⼯程;点击“完成”,之后:显⽰你创建的⼯程的信息。
2,再在有⼀个的⼯程的条件下,我们再建⽴⼀个源⽂件;“⽂件”——“新建”(快捷键Ctri+N),出现:建⽴源⽂件,选择“C++Source”,⼀般都是建⽴这种⽂件的(适⽤在当⽂件中适⽤)如果要建⽴头⽂件的话,选择“C/C++Header File”,(适⽤在多⽂件⼯程中使⽤)命名,⽂件名称,点击“确定”,之后:进⼊编辑区,在主界⾯编写代码:如下编写完之后呢:可以按编译按钮调试程序,看看有没有错误,有的话改正,没有的话就可以再按连接按钮检查连接(多⽂件⼯程时常⽤,检查⽂件间是否正常连接),最后,点运⾏按钮,就可以运⾏了如果是有代码如:cpp⽂件,或.h⽂件,想添加都VC6.0⾥的话,请下⾯:⽂件扩张名是.h,代表的话头⽂件,⼀般是书写⼀些函数原型,以及⼀些在整个程序中常⽤到的结构体,频繁使⽤的函数说明,定义等等;⽂件扩张名为,cpp的,是C++中的源⽂件,也是最常⽤到的⽂件,每建⽴⼀个⼯程都要⾄少⼀个源⽂件(⾄少要有⼀个函数⼊⼝——主函数main()),包含了核⼼代码;建⽴与运⾏说明:(以VC6.0编译器为例,其他编译器类似)⾸先,打开VC6.0编译环境;在菜单栏——⽂件(的下拉菜单中选择“新建”),在弹出的选择窗⼝中,选择Win32Console Application(控制台应⽤程序),在填写程序名称,选择⼀个程序保存路径,点击“完成”,查看⼯程信息在点击“确定”,级建⽴⼀个简单的⼯程了!再点击左边的⼯程信息右下⾓的“FileView”选项;可以看到你新建的⼯程,再双击你新建的⼯程名可以查看⼯程的信息在双击⼯程⽂件,在这⾥是777.files,可以看到该⼯程的包含的⽂件:其中,Source Files为包含所有⼯程的源⽂件Header Files为包含所有⼯程的头⽂件在源⽂件选项“Source Files”,右键单击中的“添加⽬录到⼯程”,添加你要打开的扩展名为.cpp的源⽂件在头⽂件选项“Header Files”,右键单击中的“添加⽬录到⼯程”,添加你要打开的扩展名为.h的头⽂件添加完你所有的头⽂件和源⽂件之后,检查⼀下是否添加完毕,之后就可以编译了,其中第⼆个按钮为编译按钮,可以找出⼯程的错误信息,有错误修改,没错误就可以跳到连接,编译右边的按钮,即第三个按钮(多⽂件⼯程⼀定要连接,查看⽂件是否准确相连接)当编译,连接都没有错误时,可以按运⾏按钮,即可以运⾏了,^_^。
.c和.h文件的区别
.c和.h文件的区别一个简单的问题:.c和.h文件的区别学了几个月的C语言,反而觉得越来越不懂了。
同样是子程序,可以定义在.c文件中,也可以定义在.h文件中,那这两个文件到底在用法上有什么区别呢?2楼:子程序不要定义在.h中。
函数定义要放在.c中,而.h只做声明.否则多引用几次,就会发生函数重复定义的错误。
3楼:.h只做声明,编译后不产生代码4楼:这样做目的是为了实现软件的模块化使软件结构清晰,而且也便于别人使用你写的程序纯粹用 C 语言语法的角度,你当然可以在.h 中放任何东西,因为#include 完全等价于把.h 文件Ctrl-C Ctrl-V 到.c 中.h 中应该都是一些宏定义和变量、函数声明,告诉别人你的程序“能干什么、该怎么用”.c 中是所有变量和函数的定义,告诉计算机你的程序“该怎么实现”5楼:当然,如果一个.h 被多个.c 包含而且.h 中有对象(变量或函数)的定义,就会发生重复定义的错误了声明可以无穷多次,定义只能一次6楼:一般来说,一个C文件应该是一个模块如果你的程序仅仅有一个模块(仅仅一个C文件),就可以不用建立H文件了。
否则你的模块肯定不是独立的,你的模块里面的实现要被别的模块调用。
这个时候你最好生成一个头文件(H文件),在头文件里面可以声明你的那些函数是公共的。
当别的模块包含你的头文件后,就可以使用你的公共声明了。
7楼:一个C对应一个H,这样管理起来方便比如你有一个"feed_dog.c",那么就再添加一个"feed_dog.h":#ifndef _feed_dog_h#define _feed_dog_hextern void feed_dog(void);#endif其实在H文件里写函数也无所谓,只是不符合习惯而已。
只要按照以上的格式写,一个H文件添加多少次都无所谓,呵呵8楼:只是一种约定在编译器里面,.c和.h是没有区别的,.c和.h如何使用完全取决于程序员,不过为了你的程序以后还能看懂而且别人也能看懂,请遵守普遍的约定,这些约定前面的大虾们已经讲了很多了.这个就象汽车在马路上要靠右行使一样,是人为约定,汽车(编译器)本身并不知道自己是在靠左还是靠右行使.如果你喜欢,还可以用任意后缀命名源文件和头文件,但这样干可能会导致集成编译和调试环境罢工,你只好自己写makefile文件了.9楼:非常感谢各位大侠,不过我现在越来越糊涂了1,当一个函数要经常使用(比如有十几个C文件使用它)时,一般我都放在H文件里,并在前面加上__inline.对于__inline 函数,很多C文件都可以INCLUDE这个H文件,但是它好象只能被一个H文件INCLUDE,如果有两个H文件INCLUDE它,就会出现编译错误。
.h文件——精选推荐
.h⽂件
“.h⽂件是C语⾔和【C++】语⾔的头⽂件,⼀般在【.h】类的头⽂件⾥⾯只放⼊函数声明,宏定义,函数原型;.cpp⽂件是源⽂件,⼀般都是在⼀个项⽬中。
”
简单的功能使⽤源⽂件(也就是.cpp)就⾜够编写,如书本上最基本的“Hello World”编码,只要在源⽂件中有⼀个主函数就可以完成⼀个程序。
稍微复杂⼀点的程序中,也许就会⽤到头⽂件(.h)。
事实上,这种头⽂件和代码中预处理⾥包含的头⽂件没有什么区别(就好像C语⾔中#include <stdio.h>)其中stdio.h就是⼀个头⽂件。
编写头⽂件就是按照⾃⼰的需要,给程序设计这样的头⽂件。
头⽂件中,⼀般包含⼀些类的声明,函数定义之类的东西,⽅便在源⽂件的主函数中使⽤。
例如在a.h⽂件中:
#include <iostream>
using namespace std;
class Try
{
public:
void do();
}
接下来,只要在源⽂件b.cpp中的预处理命令⾥写成:
#include <iostream>
#include "a.h" (也就是在这⾥加上#include "a.h"这⼀句)
using namespace std;
.....
就可以在b.cpp的代码中声明和调⽤Try类型的对象了。
c和h的区别
C语言中、h与、c文件解析(很精彩)简单的说其实要理解C文件与头文件(即、h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程:1、预处理阶段2、词法与语法分析阶段3、编译阶段,首先编译成纯汇编语句,再将之汇编成跟CPU相关的二进制码,生成各个目标文件(、obj文件)4、连接阶段,将各个目标文件中的各段代码进行绝对地址定位,生成跟特定平台相关的可执行文件,当然,最后还可以用objcopy生成纯二进制码,也就就是去掉了文件格式信息。
(生成、exe文件)编译器在编译时就是以C文件为单位进行的,也就就是说如果您的项目中一个C文件都没有,那么您的项目将无法编译,连接器就是以目标文件为单位,它将一个或多个目标文件进行函数与变量的重定位,生成最终的可执行文件,在PC上的程序开发,一般都有一个main函数,这就是各个编译器的约定,当然,您如果自己写连接器脚本的话,可以不用main函数作为程序入口!!!!(main 、c文件目标文件可执行文件)有了这些基础知识,再言归正传,为了生成一个最终的可执行文件,就需要一些目标文件,也就就是需要C文件,而这些C文件中又需要一个main函数作为可执行程序的入口,那么我们就从一个C文件入手,假定这个C文件内容如下:#include <stdio、h>#include "mytest、h"int main(int argc,char **argv){test = 25;printf("test、、、、、、、、、、、、、、、、、%d\n",test);}mytest、h头文件内容如下:int test;现在以这个例子来讲解编译器的工作:1、预处理阶段:编译器以C文件作为一个单元,首先读这个C文件,发现第一句与第二句就是包含一个头文件,就会在所有搜索路径中寻找这两个文件,找到之后,就会将相应头文件中再去处理宏,变量,函数声明,嵌套的头文件包含等,检测依赖关系,进行宏替换,瞧就是否有重复定义与声明的情况发生,最后将那些文件中所有的东东全部扫描进这个当前的C文件中,形成一个中间"C文件"2、编译阶段,在上一步中相当于将那个头文件中的test变量扫描进了一个中间C文件,那么test变量就变成了这个文件中的一个全局变量,此时就将所有这个中间C文件的所有变量,函数分配空间,将各个函数编译成二进制码,按照特定目标文件格式生成目标文件,在这种格式的目标文件中进行各个全局变量,函数的符号描述,将这些二进制码按照一定的标准组织成一个目标文件3、连接阶段,将上一步成生的各个目标文件,根据一些参数,连接生成最终的可执行文件,主要的工作就就是重定位各个目标文件的函数,变量等,相当于将个目标文件中的二进制码按一定的规范合到一个文件中再回到C文件与头文件各写什么内容的话题上:理论上来说C 文件与头文件里的内容,只要就是C语言所支持的,无论写什么都可以的,比如您在头文件中写函数体,只要在任何一个C文件包含此头文件就可以将这个函数编译成目标文件的一部分(编译就是以C文件为单位的,如果不在任何C文件中包含此头文件的话,这段代码就形同虚设),您可以在C文件中进行函数声明,变量声明,结构体声明,这也不成问题!!!那为何一定要分成头文件与C文件呢?又为何一般都在头件中进行函数,变量声明,宏声明,结构体声明呢?而在C文件中去进行变量定义,函数实现呢??原因如下:1、如果在头文件中实现一个函数体,那么如果在多个C文件中引用它,而且又同时编译多个C文件,将其生成的目标文件连接成一个可执行文件,在每个引用此头文件的C文件所生成的目标文件中,都有一份这个函数的代码,如果这段函数又没有定义成局部函数,那么在连接时,就会发现多个相同的函数,就会报错2、如果在头文件中定义全局变量,并且将此全局变量赋初值,那么在多个引用此头文件的C文件中同样存在相同变量名的拷贝,关键就是此变量被赋了初值,所以编译器就会将此变量放入DATA段,最终在连接阶段,会在DATA段中存在多个相同的变量,它无法将这些变量统一成一个变量,也就就是仅为此变量分配一个空间,而不就是多份空间,假定这个变量在头文件没有赋初值,编译器就会将之放入BSS段,连接器会对BSS段的多个同名变量仅分配一个存储空间3、如果在C文件中声明宏,结构体,函数等,那么我要在另一个C文件中引用相应的宏,结构体,就必须再做一次重复的工作,如果我改了一个C文件中的一个声明,那么又忘了改其它C文件中的声明,这不就出了大问题了,程序的逻辑就变成了您不可想象的了,如果把这些公共的东东放在一个头文件中,想用它的C文件就只需要引用一个就OK了!!!这样岂不方便,要改某个声明的时候,只需要动一下头文件就行了4、在头文件中声明结构体,函数等,当您需要将您的代码封装成一个库,让别人来用您的代码,您又不想公布源码,那么人家如何利用您的库呢?也就就是如何利用您的库中的各个函数呢??一种方法就是公布源码,别人想怎么用就怎么用,另一种就是提供头文件,别人从头文件中瞧您的函数原型,这样人家才知道如何调用您写的函数,就如同您调用printf函数一样,里面的参数就是怎样的??您就是怎么知道的??还不就是瞧人家的头文件中的相关声明啊!!!当然这些东东都成了C标准,就算不瞧人家的头文件,您一样可以知道怎么使用c语言中、c与、h文件的困惑本质上没有任何区别。
头文件和源文件
int number1 = f1(); int number2 = f2(number1); } /* end of main.cpp */ 这 样,便是一个完整的程序了。需要注意的是,.h 文件不用写在编译器的命令之后,但它必须要在编译器 找得到的地方(比如跟 main.cpp 在一个目录下)。 main.cpp 和 math.cpp 都可以分别通过编译,生成 main.o 和 math.o,然后再把这两个目标文件进行链接,程序就可以运行了。 三、#include #include 是一个来自 C 语言的宏命令,它在编译器进行编译之前,即在预编译的时候就会起作用。 #include 的作用是把它后面所写的那个文件的内容,提的是,它本身是没有其它任何作用与副功能的,它的作用就是把每一个它出现的地方,替换成它后 面所写的那个文件的 内容。简单的文本替换,别无其他。因此,main.cpp 文件中的第一句(#include "math.h"),在编译之前就会被替换成 math.h 文件的内容。即在编译过程将要开始的时候,main.cpp 的 内容已经发生了改变:
所以,应该记住的一点就是,.h 头文件中,只能存在变量或者函数的声明, 而不要放定义。即,只能在头 文件中写形如:extern int a;和 void f();的句子。这些才是声明。如果写上 int a;或者 void f() {}这样 的句子,那么一旦这个头文件被两个或两个以上的.cpp 文件包含的话,编译器会立马报错。(关于 extern, 前面有讨论过,这里不再讨论定义跟 声明的区别了。) 但是,这个规则是有三个例外的。 一,头文件中可以写 const 对象的定义。因为全局的 const 对象默 认是没有 extern 的声明的,所以它只 在当前文件中有效。把这样的对象写进头文件中,即使它被包含到其他多个.cpp 文件中,这个对象也都只 在包含它的 那个文件中有效,对其他文件来说是不可见的,所以便不会导致多重定义。同时,因为这些.cpp 文件中的该对象都是从一个头文件中包含进去的,这样也就保证 了这些.cpp 文件中的这个 const 对象的 值是相同的,可谓一举两得。同理,static 对象的定义也可以放进头文件。 二,头文件中可 以写内联函数(inline)的定义。因为 inline 函数是需要编译器在遇到它的地方根据它的 定义把它内联展开的,而并非是普通函数那样可以先声明再链 接的(内联函数不会链接),所以编译器就需 要在编译时看到内联函数的完整定义才行。如果内联函数像普通函数一样只能定义一次的话,这事儿就难 办了。因为在 一个文件中还好,我可以把内联函数的定义写在最开始,这样可以保证后面使用的时候都可 以见到定义;但是,如果我在其他的文件中还使用到了这个函数那怎么办 呢?这几乎没什么太好的解决办 法,因此 C++规定,内联函数可以在程序中定义多次,只要内联函数在一个.cpp 文件中只出现一次,并且 在所有的.cpp 文 件中,这个内联函数的定义是一样的,就能通过编译。那么显然,把内联函数的定义放进 一个头文件中是非常明智的做法。 三,头文件中可以写类 (class)的定义。因为在程序中创建一个类的对象时,编译器只有在这个类的定义 完全可见的情况下,才能知道这个类的对象应该如何布局,所以,关于类的 定义的要求,跟内联函数是基 本一样的。所以把类的定义放进头文件,在使用到这个类的.cpp 文件中去包含这个头文件,是一个很好的 做法。在这里,值得一提 的是,类的定义中包含着数据成员和函数成员。数据成员是要等到具体的对象被 创建时才会被定义(分配空间),但函数成员却是需要在一开始就被定义的,这也就 是我们通常所说的类的 实现。一般,我们的做法是,把类的定义放在头文件中,而把函数成员的实现代码放在一个.cpp 文件中。 这是可以的,也是很好的办法。 不过,还有另一种办法。那就是直接把函数成员的实现代码也写进类定义 里面。在 C++的类中,如果函数成员在类的定义体中被定义,那么编译器会视这个函数为 内联的。因此, 把函数成员的定义写进类定义体,一起放进头文件中,是合法的。注意一下,如果把函数成员的定义写在类 定义的头文件中,而没有写进类定义中, 这是不合法的,因为这个函数成员此时就不是内联的了。一旦头 文件被两个或两个以上的.cpp 文件包含,这个函数成员就被重定义了。 五、头文件中的保护措施 考 虑一下,如果头文件中只包含声明语句的话,它被同一个.cpp 文件包含再多次都没问题——因为声明语 句的出现是不受限制的。然而,上面讨论到的头文件中的 三个例外也是头文件很常用的一个用处。那么, 一旦一个头文件中出现了上面三个例外中的任何一个,它再被一个.cpp 包含多次的话,问题就大了。因为 这三个 例外中的语法元素虽然“可以定义在多个源文件中”,但是“在一个源文件中只能出现一次”。设想一 下,如果 a.h 中含有类 A 的定义,b.h 中含有类 B 的定 义,由于类 B 的定义依赖了类 A,所以 b.h 中也 #include 了 a.h。现在有一个源文件,它同时用到了类 A 和类 B,于是程序员在这个源文件中既把 a.h 包 含进来了,也把 b.h 包含进来了。这时,问题就来了:类 A 的定义在这个源文件中出现了两次!于是整个 程序就不能通过编译了。你也许会认为这是程序 员的失误——他应该知道 b.h 包含了 a.h——但事实上他 不应该知道。 使用"#define"配合条件编译可以很好地解决这个问题。在一 个头文件中,通过#define 定义一个名字, 并且通过条件编译#ifndef...#endif 使得编译器可以根据这个名字是否被定义,再决定要不要继 续编译该 头文中后续的内容。这个方法虽然简单,但是写头文件时一定记得写进去。
第三十一篇--理一下.h和.cpp的关系
第三⼗⼀篇--理⼀下.h和.cpp的关系今天突然想到⼀个问题,我们平时写代码会将代码进⾏分类,写到不同的cpp⾥,然后要⽤到那个类⾥⾯的函数,就直接include .h⽂件就好了。
然后今天就在想,.h⾥⾯都是⼀些声明,它是怎么链接到.cpp的呢,是不是.h和.cpp需要名称相同呢,当然,我试过名称不同也是可以的。
就是因为这样,我才有了疑问,为什么引⼊.h⽂件就可以⽤相关的函数,他们是怎样关联的。
因此我做了⼀个实验:第⼀步,创建⼀个项⽬,主⽂件是main.cpp,然后创建了a.h和a.cpp,a.cpp中#include "a.h",在a.h声明void printHello(),在a.cpp⾥⾯实现它输出"hello a file"。
然后main.cpp⾥⾯#include "a.h",直接调⽤printHello(); 成功输出hello a file。
第⼆步,创建⼀个b.cpp,b.cpp中#include "a.h",同样在b.cpp⾥⾯实现输出"hello b file"。
然后运⾏,报错,说函数重定义。
第三步,将b.cpp⽂件⾥的函数名改为printHello1,在a.h中添加⼀个声明void printHello1(),在main.cpp⾥⾯再调⽤⼀个函数printHello1();成功输出“hello a file”“hello b file”。
第四步,在.h⾥⾯声明void printHello2(),运⾏,报错,printHello2()函数没有实现从这个实验中可以看出来,在⼀个项⽬中,.h⾥⾯的函数必须都有实现,并且实现不能重定义,不然会报错,后来查了⼀下资料,⾥⾯有说到.h这个头⽂件只参与编译,保证编译通过,⽽要真正⽤到函数的部分,其实是在链接部分,这个是内部进⾏操作的,会有⼀个makefile⽂件进⾏⽂件链接,指向哪个.o或者.obj。
cpp文件和h文件的区别
cpp⽂件和h⽂件的区别C++⾥⾯编译的单位是compile unit,也就是经过预处理之后的源⽂件,这包括宏的处理,以及include⽂件的替换等。
⼀般来说,h⽂件⽤于函数和变量的声明,⽽cpp⽂件则⽤于定义。
对于C++编译环境⽽⾔,他们都不过是操作系统内的⽂件,h⽂件可以include cpp⽂件,cpp⽂件也可以include h⽂件。
他们的区别是⼈们在编译/链接过程中为了⽅便的强加进去的。
单个的h⽂件也可以作为⼀个compile unit,但是如果h⽂件⾥⾯没有函数定义,那么编译器除了解析⼀遍函数原型,什么都⼲不了,不会⽣成对应的⽬标代码;如果h⽂件⾥⾯包含函数定义,这⼜分两种:内联函数和⾮内联函数。
下⾯分别讨论:1)内联函数对于内联函数,编译器会“尽量”将其每次调⽤使⽤其⽬标代码替换;注:对于内联函数的处理,主要有两种:编译期处理和链接期处理。
如果是编译期的处理,那么显然编译器在每次该函数调⽤的时候必须能够知道该函数的定义才能替换,因此⼀般是通过写在h⽂件中,这样可以被包含进每个编译单元;如果是链接期的处理,理论上说可以放在cpp⽂件,然后由链接器将对其的调⽤替换成其定义。
跟模板的实例化⼀样,⽬前的编译器⼀般都是采⽤的第⼀种⽅式,也就是编译期的处理。
因此内联函数和模板⼀般都要在h⽂件中定义。
2)⾮内联函数对于⾮内联函数,定义必须放在cpp⽂件。
否则,如果在h⽂件中定义,如果这个h⽂件被两个compile unit包含,则会⽣成该函数的两份定义,这样链接的时候,就会出现重复的定义了。
对于cpp⽂件,⼀般⽤于函数/变量的定义。
但是在函数的实现过程中,会对其他的函数/变量进⾏应⽤,这时就需要包含相应的h⽂件,告诉编译器这些函数/变量的原型是什么,⾄于这些函数/变量究竟是什么内容,放在什么位置,则是联接器关⼼的事情。
对于这种编译模型,h⽂件由于会被include在多个cpp⽂件中,因此可能会经过多次编译,这时候就要注意符号的重复定义问题;对于cpp⽂件,⼀般只会编译⼀次,不会存在上述重复定义的问题。
11.c语言中的h文件与c文件的理解、编写及使用
11.c语言中的h文件与c文件的理解、编写及使用在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模块功能的应用程序。
头文件(.h)和源文件(.cpp)的区别(c++)
头⽂件(.h)和源⽂件(.cpp)的区别(c++)头⽂件(.h)头⽂件⽤来写类的声明(包括类的成员的声明和⽅法声明)、函数原型、#define 常数等,但是很少会写出具体的实现和细节。
就好⽐抽象类⼀样。
头⽂件很有意思的是,开头和结尾必须按照以下格式:#ifndef MYCLASS_H#define MYCLASS_H// code here#endif当时我看到这个是极其的不理解和迷茫的,后来阅读了别⼈的博⽂才略懂。
⾸先解释他是⼲嘛使的,这是防⽌头⽂件被重复引⽤。
什么叫被重复引⽤?就是同⼀个头⽂件(.h)在同⼀个源⽂件(.cpp)中被include了多次。
这种错误常常是因为include嵌套。
举个最简单的例⼦,存在cellphone.h这个头⽂件引⽤了#include "huawei.h",之后⼜有china.cpp这个源⽂件同时导⼊了#include "cellphone.h" 和 #include "huawei.h"。
此时huawei.h就在⼀个源⽂件⾥引⽤了两次。
那么,某些时候,只是因为include了两遍,增⼤了编译器的⼯作量。
如果是⼩型程序的话还好说,但是⼤型⼯程甚⾄会增长⼏个⼩时的编译时间。
但是另⼀些情况,会引起很严重的错误。
⽐如在头⽂件中定义了全局变量会引起重复定义。
所以就有了我们上⾯那些看起来乱七⼋糟的代码,下⾯开始解释。
#ifndef MYCLASS_H 的意思是 if not define myclass.h,这样看就很好理解了,如果引⽤这个头⽂件的源⽂件不存在myclass.h这个头⽂件,那么接下⾏ #define MYCALSS_H,引⼊myclass.h。
然后就是我们头⽂件的代码。
如果已经有了,直接跳到 #endif。
理论上来说,上⾯这个⽚段的MYCLASS_H是可以任意命名的,但是约定俗成的,为了可读性的,我们都把它命名为这个头⽂件的⼤写和下划线的形式。
51单片机C中关于.c文件和.h文件的关系与区别
51 单片机C 中关于.c 文件和.h 文件的关系与区别C 文件,是程序设计中的一个重要概念。
所谓文件一般是指存储在外部介质上数据的集合。
一批文件是以数据的形式存放在外部介质(如磁盘)上的。
操作系统是以文件为单位对数据进行管理的,也就是说,如果想找存在外部介质上的数据,必须先按文件名找到指定的文件,然后再从该文件中读取数据。
文件是程序设计中的一个重要概念。
所谓文件一般是指存储在外部介质上数据的集合。
一批文件是以数据的形式存放在外部介质(如磁盘)上的。
操作系统是以文件为单位对数据进行管理的,也就是说,如果想找存在外部介质上的数据,必须先按文件名找到指定的文件,然后再从该文件中读取数据。
要向外部介质上存储数据也必须先建立一个文件(以文件名标识),才能向它输出数据。
1)h 文件作用1 方便开发:包含一些文件需要的共同的常量,结构,类型定义,函数,变量申明;2 提供接口:对一个软件包来说可以提供一个给外界的接口(例如:stdio.h)。
2)h 文件里应该有什幺常量,结构,类型定义,函数,变量申明。
3)h 文件不应该有什幺变量定义,函数定义。
4)extern 问题对于变量需要extern;对于函数不需要因为函数的缺省状态是extern 的。
如果一个函数要改变为只在文件内可见,加staTIc。
5)include 包含问题虽然申明和类型定义可以重复,不过推荐使用条件编译。
#ifndef_FILENAME_H #define_FILENAME_H #endif6)应该在那儿包含h 文件在需要的地方。
比如某个提供接口的h 文件仅仅被1.c 文件需要,那幺就在1.c 文件里包含。
编写的程序一般会有.H 文件和相对应的.C 文件,.H 文件是声明所用,.C 文件是其函数实现部分。
在调用时只要包含.H 文件即可,我们没有听说过#include delay.c 这类的程序,同时也不提倡使用这个形式。
在delay.h 文件中://对调用的函数声明#ifndef__DELAY_H__ #define__DELAY_H__externvoidDelayms(unsigned int n); #endif在delay.c 文件中://函数实现部分#include//for crystal11.0592MvoidDelayms(unsigned int n){unsignedinTI,j; for(j=n;j》0;j--)for(i=112;i》0;i--); }在主程序main.c 中#include //在主程序包含.h 文件,不能包含.c 文件上述方法仍然要求每建立一个工程就需要把对应的头文件复制到工程的文件夹里,这样看来仍然是比较麻烦的,这时还有另外一种方法就是将做好的头文件放在一个文件夹中,然后将这个文件夹整体拷贝到。
C++工程的文件组织
这篇文章题目叫“浅谈VC++工程的文件组织”,其实内容不光是文件组织了,内容还还很广,我很早就想写这么篇文章,一方面是总结这几年下来的经验,另一方面就是能和别人交流交流,为了不让读者在阅读中丧失兴趣,我将在文章中加入大量生动的例子,所以这篇文章内容很散,但知识本身就是一种离散的积累之后才形成关系的连贯,难道不是吗?此文的观点并不“权威”,只是我个人的观点,欢迎来信和留言,图共同进步。
1、全局变量的声明与定义一般来说,.h文件是存放定义(Definition)的地方,而.cpp文件这是存放实现的地方(Implementation)。
简单说是这样的,不过问题来了,如果你需要一个全局变量:HWND g_hwndMain;那么应该放在.h文件中,还是在.cpp文件中?对单个变量来说,这既是声明也是定义也是实现。
按照我做法,把它放到.cpp文件中,比如放到main.cpp中去。
至于.h里,根本不需要提及它。
那如果需要在别的文件中使用到这个全局变量,那应该怎么办?那就声明一下吧:extern HWND g_hwndMain;加上了extern前缀,就变成了声明,而不是定义。
如果工程中有声明g_hwndMain,但不存在“HWND g_hwndMain”这个定义的话,在link的时候就会出错。
这里顺便提一下面试时候经常问到的一个问题,在全局变量前面加上关键字static,起到什么作用?这个问题不懂就是不懂,想不出来的。
其实很简单,就是让这个全局变量只能在这个模块(文件)中使用。
为什么?因为static,extern 两者不同同时修饰一个变量,尝试“extern static HWND g_hwndMain”,这样会导致编译错误。
“extern HWND g_hwndMain”作为一个声明,是不是就一定把它放在.h文件中,不是,应该在哪里需要使用到g_hwndMain,就在哪里声明。
大家想到了,其实使用全局变量会降低程序可读性,但开发中全局变量确实又能提供很多便利,因此用不着盲目排斥它。
C++中.h与.cpp的关系
C++中.h与.cpp的关系
C++中,一般把类的定义放到头文件(.h)中,把类的实现放到源文件(.cpp)中,所以,一般在C++中,一个类一般需要一个与类同名的头文件和一个源文件。
比如定个一个类 Sample,类中定个一个私有成员变量,和两个公共成员函数,有如下代码:
//Sample.h
class Sample
{
private:
DWORD dw; //私有成员变量
public:
Sample(DWORD dw=0); //构造函数,可以不用
~Sample(); //析构函数,可以不用
void SetDw(DWORD dw); //公共成员函数 SetDw ,设置变量DWORD GetDw(); //公共成员函数 GetDw ,取得变量
};
//Sample.cpp
//代码中因为函数形参名与类成员相同,所以访问类成员变量时用了this指针,表明这是类成员变量,而不是参数。
#include "Sample.h" //头文件不可少
void Sample::Sample(DWORD dw) //构造函数的实现
{
this->dw=dw;
}
void Sample::SetDw(DWORD dw); //SetDw 成员函数的实现
{
this->dw=dw;
}
DWORD Sample::GetDw(); //GetDw 成员函数的实现
{
return this->dw; }。
.h和.cpp文件的区别
.h和.cpp⽂件的区别⾸先,所有的代码是都可以放在⼀个cpp⽂件⾥⾯的。
这对电脑来说没有任何区别,但对于⼀个⼯程来说,臃肿的代码是⼀场灾难,⾮常不适合阅读和后期维护,所以.h和.cpp⽂件更多的是对程序员的编写习惯进⾏规范⽤法1、.h⽂件直接#include到需要的.cpp⽂件⾥,就相当于把.h⽂件的代码拷贝到.cpp⽂件2、.cpp⽂件需要先⾃⼰⽣成.o⽂件,把不同.o⽂件连接⽣成可执⾏⽂件。
⽐如有3个cpp⽂件:a.cpp、b.cpp、c.cpp,其中⼀个包含main()函数,需要⽣成test程序,步骤:1、⽣成3个.o⽂件:cc -c a.cppcc -c b.cppcc -c c.cpp这样就得到3个.o⽂件:a.o、b.o、c.o2、链接⽣成test程序:cc -o test a.o b.o c.o就得到test可执⾏程序,输⼊./test就可执⾏程序了。
规范1、h⽂件⼀般包含类声明;2、cpp⽂件⼀般为同名h⽂件定义所声明的类函数说明:⼀般可在cpp⽂件直接添加main()就可以测试该模块功能。
例(g++):1//point.h2 #include<stdio.h>3 typedef struct Point Point;4struct Point{5int x,y;6 Point(int _x,int _y);7void ADD(Point _p);8void Print();9 };1//point.c2 #include"point.h"3#define DEBUG 14 Point::Point(int _x,int _y){5 x=_x;6 y=_y;7 }8void Point::ADD(Point _p){9 x+=_p.x;10 y+=_p.y;1112▽oid Point::Print(){13 printf("(%d,%d)\n",x,y);14 }1516#if DEBUG17int main(){18 Point a(1,1);19 Point b(2,2);20 a.Print();21 a.ADD(b);22 a.Print();23return0;24 }25#endif执⾏:g++ -c point.cg++ -o test point.o获得可执⾏程序test执⾏test,可得到结果:[zjp@virtual-CentOS-for-test workstation]$ ./test (1,1)(3,3)。
C++中template的.h文件和.cpp文件的问题
C++中template的.h⽂件和.cpp⽂件的问题在C++中,⽤到类模板时,如果类似⼀般的类声明定义⼀样,把类声明放在.h⽂件中,⽽具体的函数定义放在.cpp⽂件中的话,会发现编译器会报错。
如类似下⾯代码://test.h⽂件#ifndef TEST_H_#define TEST_H_template <class T>class test{private:T a;public:test();};#endif//test.cpp⽂件#include "test.h"template <class T>test<T>::test(){a = 0;}//main.cpp⽂件#include <iostream>#include "test.h"using namespace std;int main(){test<int> abc;}以上代码在编译时会产⽣如下错误:Error 2 error LNK1120: 1 unresolved externalsError 1 error LNK2019: unresolved external symbol "public: __thiscall test<int>::test<int>(void)" (??0?$test@H@@QAE@XZ) referenced in function _main原因在于,类模版并不是真正的类,它只是告诉编译器⼀种⽣成类的⽅法,编译器在遇到类模版的实例化时,就会按照模版⽣成相应的类。
在这⾥就是编译器遇到main函数中的test<int> abc;时就会去⽣成⼀个int类型的test类。
⽽每⼀个cpp⽂件是独⽴编译的,那么如果将类模版的成员函数单独放在⼀个cpp⽂件中,编译器便⽆法确定要根据什么类型来产⽣相应的类,也就造成了错误。
C语言中.h与.c解析
(1)、混淆你的概念,让你无法分析出几个物理过程,或某个物理过程遵循的那条物理定律;
(2)、存在高次方程,列出方程也解不出。而后者已经是数学的范畴了,所以说,最难之处还在于掌握清晰的概念;
程序设计也是如此,如果概念很清晰,那基本上没什么难题(会难在数学上,比如算法的选择、时间空间与效率的取舍、稳定与资源的平衡上)。但是,要掌握清晰的概念也没那么容易。比如下面这个例子,看看你有没有很清晰透彻的认识。
2、答:1中已经回答过了。
3、答:不会。问这个问题的人绝对是概念不清,要不就是想混水摸鱼。非常讨厌的是中国的很多考试出的都是这种烂题,生怕别人有个清楚的概念了,绝对要把考生搞晕。
搞清楚语法和概念说易也易,说难也难。窍门有三点:
不要晕着头工作,要抽空多思考思考,多看看书;
看书要看好书,问人要问强人。烂书和烂人都会给你一个错误的概念,误导你;
int main(int argc,char **argv)
{
test = 25;
printf("test.................%d\n",test);
}
头文件内容如下:
int test;
现在以这个例子来讲解编译器的工作:
c++include.h.cpp的区别
c++include.h.cpp的区别背景说明在⾯向对象编程的过程中,为了结构清晰,通常将不同的类定义在不同的⽂件⾥使⽤时通过include .h⽂件即可,不⽤include .cpp正常情况下,定义⼀个类,将声明写在.h⽂件中,将实现写在.cpp⽂件中,.cpp⽂件中include .h⽂件即可但是,我这个类不是通过IDE创建的,⽽是我⾃⼰新建⽂件,⾃⼰写出来的,其实这⾥就是问题所在.h⽂件#pragma onceclass duoxiangshi{private:int a[100]={0};int maxexponent;public:duoxiangshi(int *p,int maxexponent);~duoxiangshi();void printdxs();friend duoxiangshi dxs_minus(duoxiangshi dxs1,duoxiangshi dxs2);};.cpp⽂件#include "duoxiangshi.h"#include <iostream>using namespace std;duoxiangshi::duoxiangshi(int *p=NULL,int maxexponent=0){this->maxexponent=maxexponent;if(p!=NULL){for(int i=0;i<=maxexponent;i++){a[i]=p[i];}}}void duoxiangshi::printdxs(){if(a[0]!=0)cout<<1<<'+';for(int i=1;i<maxexponent;i++){if(a[i]!=0)cout<<"x^"<<i<<'+';}if(a[maxexponent]!=0)cout<<"x^"<<maxexponent<<endl;}duoxiangshi::~duoxiangshi(){}duoxiangshi dxs_minus(duoxiangshi dxs1,duoxiangshi dxs2){duoxiangshi temp=duoxiangshi();int maxexpo=dxs1.maxexponent;//dxs1-dxs2for(int i=maxexpo;i>=0;i--){temp.a[i]=dxs1.a[i]-dxs2.a[i];if(temp.a[i]<0)temp.a[i]*=-1;}for(int i=maxexpo;i>=0;i--){if(temp.a[i]==0){--maxexpo;}else{break;}}temp.maxexponent=maxexpo;return temp;}但是这次在main函数所在⽂件开头include .h ⽂件却报错,未定义之类的错误后来试了⼀下include .cpp⽂件,成功运⾏不难想到,IDE在创建项⽬的时候,会有额外的⽂件记录项⽬的组成和依赖关系等信息,以⽅便编译运⾏⽐如vs就是利⽤.sln(solution)解决⽅案⽂件做到这点的,当然⾥⾯还有其他信息SLN ( own's the following details):* A list of the projects that are to be loaded into Visual Studio 2005* A list of project dependencies* Microsoft Visual SourceSafe information* A list of add-ins that are available以下就当作在vs环境下创建项⽬该类是我⾃⼰创建⽂件并编写的,没有使⽤IDE创建类的接⼝,因此.sln的⽂件没有记录我创建的类⽂件的信息仔细回想⼀下,include 对应的.h⽂件⽽不⽤include .cpp⽂件就可以运⾏确实需要额外的信息编译器可以⾃动找到对应的.cpp实现⽂件将其链接编译分析下解决⽅案的作⽤通过IDE创建类会⾃动将.h .cpp⽂件加⼊解决⽅案,并且⼀⼀对应,链接编译时读取解决⽅案遇到.h⽂件声明,将对应的.cpp⽂件也进⾏处理⽽不在解决⽅案内的类⽂件.h .cpp则不会被编译器识别所以需要利⽤#include命令将.cpp⽂件(定义实现)包含进啦(相当于复制.cpp⽂件的内容放在这⾥)只是#include .h⽂件仅仅将声明加⼊进来,编译器找不到.cpp中的定义实现所以才会出现开头的错误因此,开头引⼊.h⽂件,在⽂件的最后#include .cpp⽂件同样可以运⾏,这也证明了#include .cpp就是复制内容加⼊进来这个时候应该将#include .h⽂件理解为声明#include .cpp⽂件理解为实现(代码复制拷贝)平时写代码时也是这样,调⽤某个函数,前⾯要么把该函数定义了,要么声明⼀下,然后在后⾯定义在⾃⼰创建类⽂件(没有加⼊解决⽅案)的时候应该在开头(函数调⽤前)#include .cpp把定义加⼊进来或者在开头(函数调⽤前)加⼊声明#include .h,在后⾯加⼊定义#include .cpp。
C++中.h与.hpp文件的区别
C++中.h与.hpp⽂件的区别c++中的.hpp⽂件hpp,其实质就是将.cpp的实现代码混⼊.h头⽂件当中,定义与实现都包含在同⼀⽂件,则该类的调⽤者只需要include该hpp⽂件即可,⽆需再将cpp加⼊到project中进⾏编译。
⽽实现代码将直接编译到调⽤者的obj⽂件中,不再⽣成单独的obj,采⽤hpp将⼤幅度减少调⽤ project中的cpp⽂件数与编译次数,也不⽤再发布烦⼈的lib与dll,因此⾮常适合⽤来编写公⽤的开源库。
1、是Header Plus Plus 的简写。
2、与*.h类似,hpp是C++程序头⽂件。
3、是VC专⽤的头⽂件,已预编译。
4、是⼀般模板类的头⽂件。
5、⼀般来说,*.h⾥⾯只有声明,没有实现,⽽*.hpp⾥声明实现都有,后者可以减少.cpp的数量。
6、*.h⾥⾯可以有using namespace std,⽽*.hpp⾥则⽆。
7、*.hpp要注意的问题有:a)不可包含全局对象和全局函数由于hpp本质上是作为.h被调⽤者include,所以当hpp⽂件中存在全局对象或者全局函数,⽽该hpp被多个调⽤者include时,将在链接时导致符号重定义错误。
要避免这种情况,需要去除全局对象,将全局函数封装为类的静态⽅法。
b)类之间不可循环调⽤在.h和.cpp的场景中,当两个类或者多个类之间有循环调⽤关系时,只要预先在头⽂件做被调⽤类的声明即可,如下:class B;class A{public:void someMethod(B b);};class B{public:void someMethod(A a);};在hpp场景中,由于定义与实现都已经存在于⼀个⽂件,调⽤者必需明确知道被调⽤者的所有定义,⽽不能等到cpp中去编译。
因此hpp中必须整理类之间调⽤关系,不可产⽣循环调⽤。
同理,对于当两个类A和B分别定义在各⾃的hpp⽂件中,形如以下的循环调⽤也将导致编译错误://a.hpp#include "b.hpp"class A{public:void someMethod(B b);};//b.hpp#include "a.hpp"class B{public:void someMethod(A a);}c)不可使⽤静态成员静态成员的使⽤限制在于如果类含有静态成员,则在hpp中必需加⼊静态成员初始化代码,当该hpp被多个⽂档include时,将产⽣符号重定义错误。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
就可以分别放在一个单元,也就是cpp里面)
那么就是一个.cpp对应一个.obj,然后将所有的obj链接起来(通过一个叫链接器的程序),
组成一个.exe,也就是程序了.
如果一个.cpp要用到另一个.cpp定义的函数怎么办? 只需在这个.cpp种写上他的函数声明
声明,因为c++这种语言,在使用函数和变量的时候,必须将他声明,为何要声明?声明之后才
知道他的规格,才能更好的发现不和规格的部分.你别妄想一个编译单元,会自动从另一个
编译单元那里得到什么信息,知道你是如何定义这个函数的.
所以说,只要使用到该函数的单元,就必须写一份声明在那个.cpp里面,这样是不是很麻烦,
进来.
这时候实际上a.cpp和b.cpp都有一个func()函数的定义.
如果这个函数是内部链接static的话,还好,浪费了一倍空间;
如果是extern,外部链接(这个是默认情况),那么根据在同一个程序内不可出现
同名函数的要求,连接器会毫不留情给你一个连接错误!
如果在里面写代码,当其他.cpp包含他的时候,就会出现重复定义的情况,
比如将函数func(){printf};放到文件a.h,里面还有一些a.cpp需要的声明等;
然后你发现b.cpp需要用到a.cpp里面的一个函数,就很高兴的将a.h包含进来.
注意,#include并不是什么申请指令,他就是将指定的文件的内容,原封不动的拷贝
而且,如果要修改,就必须一个一个修改.这真让人受不了.
.h就是为了解决这个问题而诞生,他包含了这些公共的东西.然后所有需要使用该函数的.cpp,只需要
用#include包含进去便可.以后需要修改,也只是修改一份内容.
请注意不要滥用.h,.h里面不要写代码,.h不是.cpp的仓库,什么都塞到里面.
公用的,还是只是在一个编译单元obj里面使用的.
这些关键字就是extern 和 static; extern是外部链接的意思,也就是除了这个单元,外部的单元
也是能够访问这个函数的.static 是内部链接,自属于自己单元.
说了这么久,还没有说.h的作用呢?
其实没有.h也能很好的工作,但是当你发现一个外部链接的函数或外部变量,需要许多份
就可以了.其余工作由链接器帮你完成,你可以随便调用该函数.
链接器将所有的obj连接起来,但是如果碰巧有相同的函数或外部变量怎么办?他如何识别?
一般来说是不能允许在同一个程序中,出现两个一样的函数名或外部变量名.
但是只得庆幸的是,c++可以通过一种叫做链接属性的关键字来限定,你这个函数是属于整个程序
.h和.cpp文件的区别
关于头文件和源文件的分别
首先,我们可以将所有东西都放在一个.cpp文件内.
然后编译器就将这个.cpp编译成.obj,obj是什么东西?
就是编译单元了.一个程序,可以由一个编译单元组成,
也可以有多个编译单元组成. 如果你不想让你的源代码变得很难阅读的话,