c++ *.h和*.cpp在编译中的作用
首先,我们可以将所有东西都放在一个.cpp文件内.然后编译器就将这个.cpp编译成.obj,obj是什么东西?就是编译单元了.
一个程序,可以由一个编译单元组成,也可以有多个编译单元组成. 如果你不想让你的源代码变得很难阅读的话,就请使用多个编译单元吧.(一个函数不能放到两个编译单元里面,但两个以上就可以分别放在一个单元,也就是cpp里面)那么就是一个.cpp对应一个.obj,然后将所有的obj链接起来(通过一个叫链接器的程序),组成一个.exe,也就是程序了.
如果一个.cpp要用到另一个.cpp定义的函数怎么办? 只需在这个.cpp种写上他的函数声明就可以了.其余工作由链接器帮你完成,你可以随便调用该函数.链接器将所有的obj连接起来,但是如果碰巧有相同的函数或外部变量怎么办?他如何识别?一般来说是不能允许在同一个程序中,出现两个一样的函数名或外部变量名.但是只得庆幸的是,c++可以通过一种叫做链接属性的关键字来限定,你这个函数是属于整个程序公用的,还是只是在一个编译单元obj里面使用的.这些关键字就是extern 和 static; extern是外部链接的意思,也就是除了这个单元,外部的单元也是能够访问这个函数的.static 是内部链接,自属于自己单元.说了这么久,还没有说.h的作用呢?其实没有.h也能很好的工作,但是当你发现一个外部链接的函数或外部变量,需要许多份声明,因为c++这种语言,在使用函数和变量的时候,必须将他声明,为何要声明?声明之后才知道他的规格,才能更好的发现不和规格的部分.你别妄想一个编译单元,会自动从另一个编译单元那里得到什么信息,知道你是如何定义这个函数的.所以说,只要使用到该函数的单元,就必须写一份声明在那个.cpp里面,这样是不是很麻烦,而且,如果要修改,就必须一个一个修改.这真让人受不了..h就是为了解决这个问题而诞生,他包含了这些公共的东西.然后所有需要使用该函数的.cpp,只需要用#include包含进去便可.以后需要修改,也只是修改一份内容.请注意不要滥用.h,.h里面不要写代码,.h不是.cpp的仓库,什么都塞到里面.如果在里面写代码,当其他.cpp包含他的时候,就会出现重复定义的情况,比如将函数func(){printf};放到头文件a.h,里面还有一些a.cpp需要的声明等;然后你发现b.cpp需要用到a.cpp里面的一个函数,就很高兴的将a.h包含进来.注意,#include并不是什么申请指令,他就是将指定的文件的内容,原封不动的拷贝进来.这时候实际上a.cpp和b.cpp都有一个func()函数的定义.如果这个函数是内部链接static的话,还好,浪费了一倍空间;如果是extern,外部链接(这个是默认情况),那么根据在同一个程序内不可出现同名函数的要求,连接器会毫不留情给你一个连接错误!;如果你还不太理解.那么就尝试不用h,只用多个cpp看看应该如何写.尝试在两个cpp中写同名函数.看看是否链接出错.尝试在cpp使用其他cpp定义的函数.看看应该如何做.
头文件是没有编译意义的,一般只是编译.cpp生成.obj.但是.cpp里面有#include将指定头文件(其实任何文件都行)插进来,组成完整的.cpp.如果你不喜欢这个方式,你也可以直接在.cpp里面写好了,而不放到.h里面,载用指令拷贝进来.头文件是工具,但不是必须.
个人认为:
.cpp内用于(1)函数实现(包括全局函数(默认)、静态函数)。
(2)全局变量、静态变量定义。
(3)静态函数声明,静态变量声明。(指定编译单元内部使用的函数和变量)
.h内用于 (1)全局函数声明,注意静态函数不包括在内。
(2)全局变量声明,无静态变量。
--------------------------------------------------------------------------------------------------------------
我的一点总结 by ordedere
上文说到,#include并不是什么申请指令,他就是将指定的文件的内容,原封不动的拷贝进来。所以我们可以将.h的代码连接到.cpp的前端,从而可以更加清晰的看到:
a.h, b.cpp & c.cpp 都同时include了a.h,那么b.cpp其实可以看做是文件:a.h+b.cpp连接而成的cpp源码;而a.h+c.cpp连接成的源码等价于c.cpp include a.h。
那么对于变量在.h中的声明,对cpp有如下情况的分类:
在.h中声明变量int a,等价于在.cpp的前端声明(或者定义)变量全局变量int a;
在.h中声明外部变量extern int a; 等价于在.cpp 的前端声明了外部变量a;所以这个变量a被指明在其他cpp文件中定义;
在.h中声明全局变量 static int a; 等价于在所有包含.h的cpp中将有文件内部的变量a,且每个include该h文件的cpp中的a变量的地址是不同的,也就是原作者说道的空间浪费问题。
同理,对于函数的声明:
在.h 中声明静态(static)函数,就相当于在所包含该头文件的cpp程序中需要定义该静态函数;
在.h中声明外部(extern)函数,即指明该函数的定义是在其他源文件中。
在.h中声明普通函数,即在cpp的开始部分声明一个函数是一个道理。
所以:静态函数和全局静态变量的声明应该在cpp中(毕竟静态的意义就是确保该函数或者变量的作用空间仅限于该源文件内部),而避免在.h中有静态变量或函数的声明。
c++ *.h和*.cpp在编译中的作用的更多相关文章
- C++编译与链接(0)-.h与.cpp中的定义与声明
C++中有的东西需要放在可以在.h文件中定义,有的东西则必须放在.cpp文件中定义,有的东西在不同的cpp文件中的名字可以一样,而有的则不能一样 那么究竟哪些东西可在头文件中定义,声明,哪些东西又必须 ...
- 解决Visual C++工程中包含 .c 或cpp文件编译时产生的.pch预编译头错误(C1853)的办法
2014-01-17 23:36 5128人阅读 评论(1) 收藏 举报 分类: 资料集(282) 版权声明:本文为博主原创文章,未经博主允许不得转载. 之前使用网上的一个开源代码,被封装成Windo ...
- template 不能分别在.h和.cpp中定义模板
先上代码: #ifndef SEQLIST_H #define SEQLIST_H #include <iostream> ; template <typename type> ...
- Qt Creator 中,如何更改h,cpp,ui的文件并不让ui失效
这个星期在使用qt,碰到一个很蛋疼的问题:创建对话框的时候,不小心输错了名字.而且是在很迟才发现的.这个时候对话框都已经布局差不多了,为了改名字,碰到更蛋疼的问题,改了名字后就无法使用转到槽的功能了. ...
- makefile多目录的.c 格式.cpp混合编译
# # c.cpp混合编译的makefile模板 # # BIN = test.exe CC = gcc CPP = g++ #这里只加入库头文件路径及库路径 INCS = -I"c:/mi ...
- android 源码编译中的错误 解决
1.编译种错误提示: arm-none-linux-gnueabi-gcc: directory: No such file or directory arm-none-linux-gnueabi-g ...
- include .h 以及.cpp的记录
VC include 路径解析要了解vc中使用#include命令包含头文件所搜寻的路径,必须先了解vc中的几种路径:1. 系统路径 系统路径在vc中是"Tools->Options- ...
- makefile编写---.c .cpp 混合编译makefile 模板
# c.cpp混合编译的makefile模板 # # BIN = client_system BASE_INSTALL_DIR := /opt/arm-2009q1 BUILD_TOOL_DIR := ...
- 第三十一篇 -- 理一下.h和.cpp的关系
今天突然想到一个问题,我们平时写代码会将代码进行分类,写到不同的cpp里,然后要用到那个类里面的函数,就直接include .h文件就好了.然后今天就在想,.h里面都是一些声明,它是怎么链接到.cpp ...
随机推荐
- 《Linux内核设计与实现》CHAPTER18阅读梳理
<Linux内核设计与实现>CHAPTER18阅读梳理 [学习时间:2hours] [学习内容:bug的来源分析:bug调试途径] 一.bug来源 1.内核中的bug 内核中的bug表现得 ...
- 单身狗进化——求n!的位数
题目: 分析: 这道题目要求的是n!的位数,显然一种思路是先求出n!的值,假定为res,然后再计算res的位数,这种方法在n比较小时是可以的,如果res为int型,一旦n>16,res就会超出i ...
- LeetCode Maximum Size Subarray Sum Equals k
原题链接在这里:https://leetcode.com/problems/maximum-size-subarray-sum-equals-k/ 题目: Given an array nums an ...
- java-Filter过滤器
特点 过滤浏览器请求的java程序 处于浏览器和被请求的资源之间 可以有多个过滤器组成过滤链 有配置的顺序决定先后顺序 常用语设置请求和响应的字符集 API doFilter()执行过滤 Filter ...
- PHP---------PHP函数里面的static静态变量
工作一年了,一年里很少用到static这个关键词,不管是类里面还是方法里面基本都没怎么用过.平时看到类里面有这个都没什么好奇的,今天在函数里面看到了这个,就去百度了一下. <?phpfuncti ...
- C# 窗体(登录界面)
首先拖动一个 lable(写用户名) 后面 跟一个Textbox 再lable(写密码) 后面 跟一个Textbox(需设置一下属性—行为—useSystemPasswordChar(默认输入的密 ...
- 使用@Configuration注解来代替Spring的bean配置
下面是一个典型的Spring配置文件(application-config.xml): <beans> <bean id="orderService" class ...
- IIS7 应用程序池设置成 经典 v2.0
HTTP 错误 500.21 - Internal Server Error 处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipe ...
- 郑轻校赛题目 问题 G: 多少个0
问题 G: 多少个0 时间限制: 1 Sec 内存限制: 128 MB提交: 192 解决: 40 题目描述 一个n*n的方格,每个格子中间有一个数字是2或者5,现在从方格的左上角走到右下角,每次 ...
- 【转】PowerShell入门(三):如何快速地掌握PowerShell?
转至:http://www.cnblogs.com/ceachy/archive/2013/02/01/HowToLearnPowerShell.html 如何快速地掌握PowerShell呢?总的来 ...