c++中头文件与实现文件的关系(reprint) 转载于Search的博客

C语言头文件&& 实现文件 && 工程文件组织 C语言头文件&& 实现文件 && 工程文件组织 一 .h .cpp 文件     先来看看这些文件的编译连接过程,然后引出一些具体的问题,如.h文件的相关作用、头文件编写规则、   (1)编译、链接     先来分析下下面这个小例子: //a.h class   A { pubic:       int   f(int   t); }; //a. 阅读详情

原文地址 :http://xiangyanglai.blog.163.com/blog/static/2047252022012715103338279/

点击打开链接


关于两者以前的关系,要从N年以前说起了~ long long ago,once aupon a time .......

那是一个被 遗忘的年代,在编译器只认识.c(.cpp))文件,而不知道.h是何物的年代。
那时的人们写了很多的.c(.cpp)文件,渐渐地,人们发现在 很多.c(.cpp)文件中的声明语句就是相同的,但他们却不得不一个字一个字地重复地将这些内容敲入每个.c(.cpp)文件。但更为恐怖的是,当其中 一个声明有变更时,就需要检查所有的.c(.cpp)文件,并修改其中的声明,啊~简直是世界末日降临!
终于,有人(或许是一些人)再不能忍受这 样的折磨,他(们)将重复的部分提取出来,放在一个新文件里,然后在需要的.c(.cpp)文件中敲入#include   XXXX这样的语句。这样即使某个声明发生了变更,也再不需要到处寻找与修改了---世界还是那么美好!
因为这个新文件,经常被放 在.c(.cpp)文件的头部,所以就给它起名叫做“头文件”,扩展名是.h.
从此,编译器(其实是预处理器)就知道世上除了.c(.cpp)文 件,还有个.h的文件,以及一个叫做#include命令。

虽然后来又发生很多的变化,但是这样的用法一直延续至今,只是时日久远了,人们便淡忘了当年的缘由罢了。
提到了头文件,就说说它的作用吧~
想 到了林锐GG写的高质量C/C++编程上头文件的作用的简短描述:
(1)通过头文件来调用库功能。在很多场合,源代码不便(或不准)向用户公布, 只要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库功能,而不必关心接口怎么实现的。编译器会从库中提取相应的代码。
(2) 头文件能加强类型安全检查。如果某个接口被实现或被使用时,其方式与头文件中的声明不一致,编译器就会指出错误,这一简单的规则能大大减轻程序员调试、改 错的负担。


预处理是编译器的前驱,作用是把存储在不同文件里的程序模块集成为一个完整的源程序.
#include本身只是一个简单的文件包含 预处理命令,即为把include的后面文件放到这条命令这里,除此之外,没有其它的用处(至少我也样认为).


我对乾坤一笑兄的观点,十分赞同,基础的东东一定要弄明白.
我下面就乾坤一笑兄的例子做讲,完备他的一些让人迷惑不解的时候~

例子:
//a.h
void foo();


//a.c
#include "a.h"  //我的问题出来了:这句话是要,还是不要?
void foo()
{
    return;
}

//main.c
#include "a.h"
int main(int argc, char *argv[])
{
   foo(); 
  return 0;

针对上面的代码,请回答三个问题: 
a.c 中的 #include "a.h" 这句话是不是多余的? 
1.为什么经常见 xx.c 里面 include 对应的 xx.h? 
2.如果 a.c 中不写,那么编译器是不是会自动把 .h 文件里面的东西跟同名的 .c 文件绑定在一起? 
3.第三个问题我给他改了一下:如果 a.c 中不写include<>,那么编译器是不是会自动把 .h 文件里面的东西跟同名的.c文件绑定在一起?

下面是乾坤一笑的原话:

从C编译器角度看,.h和.c皆是浮云,就是改名为.txt、.doc也没有大的分别。换句话说,就是.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,都没有任何必然关系。
    这样你可能会说:啊?那我平时只想调用 xx.c 中的某个函数,却 include了 xx.h 文件,岂不是宏替换后出现了很多无用的声明?没错,确实引入了很多垃圾 ,但是它却省了你不少笔墨,并且整个版面也看起来清爽的多。鱼与熊掌不可得兼,就是这个道理。反正多些声明(.h一般只用来放声明,而放不定义,参见拙著 “过马路,左右看”)也无害处,又不会影响编译,何乐而不为呢?
翻回头再看上面的3个问题,很好解答了吧?
它的解答如下:

答:1.不一定。这个例子中显然是多余的。但是如果.c中的函数也需要调用同个.c中的其它函数,那么这个.c往往会include同名的.h,这 样就不需要为声明和调用顺序而发愁了(C语言要求使用之前必须声明,而include同名.h一般会放在.c的开头)。有很多工程甚至把这种写法约定为代 码规范,以规范出清晰的代码来。 
2.答:1中已经回答过了。 
3.答:不会。问这个问题的人绝对是概念不清,要不就是想混水摸鱼。非常 讨厌的是中国的很多考试出的都是这种烂题,生怕别人有个清楚的概念了,绝对要把考生搞晕。

over!

在此里要明确一点,编译器是按照编译单元进行编译的,所谓的编译单元,是指一个.c文件以及它所include的所有.h文件.最直观的理解就是一 个文件,一个工程中可以包含很多文件,其中有一个程序的入口点,即我们通常所说的main()函数(当然也可以没有这个函数,程序照样能启动,详细见我的 blog中).在没有这个程序入口点的情况下,编译单元只生成目标文件object file(.o文件,windows下叫做.obj).

这个例子中总共包含了二个编译单元,分别是a.c,main.c,按照我所说的,在编译阶段只是生成各自的.o文件.这个阶段不和其它的文件发生任 何的关系.
而include这个预处理指令发生在预处理阶段(早先编译阶段,只是编译器的一个前驱处理程序).


.h .c不见得是浮云,脱离了编译器谈这些没有任何的意义,抛开更深层次的这些,比如说,OS如何启动这个文件,PE结构(linux 下为elf)等等
编译器首先要识别这个文件才可能去编译它,这是前提.如果你改了它的扩展名那么你的编译器还能认识它吗~上升到一个更高的层次上 看待这个问题,XX兄说的也不错~我想XX兄说的意思就是两者不可因为名字相同就认为两者有什么关系,名字是可以随便的~
两者之间的联系,我在前 面说过了,是由于历史的原因造成的,再加上人的习惯,我想谁也不想多去记那么多文件名吧.(拿我举个例子,一个数
据表如果多于30个字段,我就觉 得头大了,现在弄的表有的多达上百个字段,真希望那位高人研究出什么好的方法来~,也让我们的世界美好一些~)

乾坤一笑的第三个问题很有代表性,多次在网上看到,现在的编译器绝对没有那么智能,而且也没有必须那么做.下面我们主要聊聊编译器的处理过程.(我 想初学者有疑问的正在于此,即是对于编译过程.h .c(.cpp)的变化不太了解,)

下面我说举个简单的例子来聊聊~
例子如下:
//a.h
class   A
{
pubic:
      int   f(int   t);
};

//a.cpp
#include   "a.h"
int   A::f(int   t)
{
    return   t;
}

//main.cpp
#include   "a.h"
void   main()
{
      A   a;
      a.f(3);
}
在预处理阶段,预处理器看到#include "文件名"就把这个文件读进来,比如它编译main.cpp,看到#include   "a.h",它就把a.h的内容读进来,它知道了,有一类A,包含一个成员函数f,这个函数接受一个int型的参数,返回一个int型的值。再往下编译很 容易就把A   a这行读懂了,它知道是要拿A这个类在栈上生成一个对象。再往下,它知道了下面要调用A的成员函数f了,参数是3,由于它知道这个函数要一个整形数用参 数,这个3正好匹配,那就正好把它放到栈上,生成一条调用f(int)函数的指令(一般可能是一句call),至于这个f(int)函数到底在哪里,它不 知道,它留着空,链接时再解决。它还知道f(int)函数要返回一个int,所以也许它也为这一点做好了准备(在例子中,我们没用这个返回值,也许它就不 处理)。再往下到文件末尾了main.cpp编译好了,生成了main.obj。整个编译过程中根本就不需要知道a.cpp的内容。
同理,编译器 再编译a.cpp,把f()函数编译好,编译a.cpp时,它也不用管别的,把f()编译好就行了。生成了a.obj。
最后一步就是链接的阶段 了,链接器把项目中所有.cpp生成的所有.obj链接起来,
在这一步中,它就明确了f(int)函数的实现所在的地址,把main.obj中空 着的这个地址位置填上正确的地址。最终生成了可执行文件main.exe。

明白了吗?不明白那就多说几句了,我们在学编译原理的时候都知道,编译器是分阶段进行的,每一个阶段将源程序从一种表示转换成另一种表示,一般情况 下都进行如下顺序:源程序->词法分器->语法分析器->语义分析器->中间代码生成器->代码优化器->代码生成 器->目标程序.
其中这中间6项活动都要涉及的两项主要活动是:符号管理器与错误处理器.
归根原因,这里有一个叫做符号表的东东在 里面让你着魔一样不明白,其实符号表是一个数据结构.编译器的基本一项功能就是要记录源程序中使用的标识符并收集与每个标识符相关的各种属性信息.属性信 息表明了该标识符的存储位置/类型/作用域(在那个阶段有效)等信息,通俗的说一下就是,当编译器看到一个符号声明时,例如你的函数名它就会把它放到这个 符号表中去登记一下~符号表里存放着你的函数的入口地址,参数个数,返回信息等等一堆东西~而在联接阶段主要是处理工程中的符号表与调用对应处理关系,即 我们通常所说的解引用.
经过前面的,不知明白与否?

最后引用一下XXX兄的结尾三点:
搞清楚语法和概念说易也易,说难也难。窍门有三点:
1.不要晕着头工作,要抽空多思考思考,多看 看书; 
2.看书要看好书,问人要问强人。烂书和烂人都会给你一个错误的概念,误导你; 
3.勤能补拙是良训,一分辛苦一分才;

TL494充电器原理维修 (转) TL494充电器原理维修 电动自行车充电器多采用开关 电源,型号虽多,但电路结构大同小异,主要区别在于所选的脉宽调制(PWM)芯片不同如(UC3845、UC3842、SG3524、TL494)。现以佳腾牌 充电器为例,介绍其原理和故障检修方法。 一、电路原理 根据实物测绘的佳腾牌充电器电路原理如图1所示。整机可分为PWM产生和推动电路、功 率开关变换电路、... 阅读详情

相关推荐

波士顿房价预测分析----以线性回归LinearRegression为例

波士顿房价数据集包括506个样本,每个样本包括13个特征变量和该地区的平均房价,房价显然和多个特征变量相关,先选择一元线性回归多个特征建立线性方程,观察模型预测的好坏,再选择多元线性回归进行房价预测。13个特征变量缩写含义CRIM城镇人均犯罪率ZN住宅用地所占比例INDUS城镇中非住宅用地所占比例CHAS虚拟变量,用于回归分析NOX环保指数RM每栋住宅的房间数AGE1940 年以前建成的自住单位的比例DIS距离 5 个波士顿的就业中心的加权距离RAD。

我走的每一步都算数 821

c++头文件实现文件关系

关于两者以前的关系,要从N年以前说起了~ long long ago,once aupon a time ....... 那是一个被 遗忘的年代,在编译器只认识.c(.cpp))文件,而不知道.h是何物的年代。 那时的人们写了很多的.c(.cpp)文件,渐渐地,人们发现在 很多.c(.cpp)文件中的声明语句就是相同的,但他们却不得不一个字一个字地重复地将这些内容敲入每个.c(

周健华的专栏 2117

基于ssm框架的java毕业设计-共享单车管理系统(源码+说明+演示视频)

基于ssm框架的java毕业设计-共享单车管理系统(源码+说明+演示视频)【项目技术】开发语言:Java框架:ssm架构:B/S数据库:mysql【实现功能】管理员功能模块:管理员登录进入共享单车管理系统可以查看首页、个人中心、用户管理、操作人员管理、停车点管理、车辆类型管理、共享单车管理、租赁单车管理、维修信息管理、归还单车管理、系统简介管理、系统管理等内容,

DEV-C++自定义头文件——自定义扩展名为.h的文件

include//这就是“头文件”return 0;“头文件”一般写成或。这行代码让一些在别的文件中定义的的函数、结构的、常量也能在此程序中调用、使用。头文件可以大大节省代码空间,内存空间。例如在bits/stdc++.h这个文件中有一个函数叫max(int x,int y),还有一个函数叫min(int x,int y),而在我自己的程序中没有定义这两个函数,可我只需在开头加上这个头文件,我就可以调用这两个函数。一般这样的头文件扩展名都是。1、打开。

m0_70379664的博客 1万+

咱们一起学C++第二十四篇:之C++头文件包含语句全解析

C++学习的道路上,我们一路同行,不断探索这门语言的各种特性。此前,我们深入学习了函数和变量的声明定义,今天,我们将把目光投向头文件和包含语句,它们在C++编程中扮演着至关重要的角色,是组织和管理代码的重要手段,对于提高代码的可读性、可维护性以及可移植性都有着深远的影响。

wj_rdk的博客 1718

c++:#include 某文件.h底层如何寻找其.cpp实现

然后,链接器负责将这些目标文件(以及任何库文件)链接成一个可执行文件或库。链接器会查找并解析在目标文件中引用的外部符号(即在其他。中正确地引用了这些声明,并生成包含对这些声明引用的机器码的目标文件。的源文件时,编译器会处理这个包含指令,将头文件的内容插入到该源文件中,但它不会直接处理实现文件(并使用其中声明的类或函数时,你实际上是在告诉编译器你希望使用这些声明。简而言之,你只需要包含头文件,而不需要包含实现文件。中定义的函数和变量),并将它们链接到最终的可执行文件中。文件中定义的函数和变量的机器码。

Ethan_Rich的博客 421

头文件(.h)实现文件(.cpp)区别

简单讲,一个Package就是由同名的.h和.cpp文件组成。当然可以少其中任意一个文件: 只有.h文件的Package可以是接口或模板(template)的定义; 只有.cpp文件的Package可以是一个程序的入口。 .cpp是C++文件的扩展名,.h主要是进行函数定义的,类中函数的声明和调用是在.cpp中的,.h文件主要是把函数进行封装,在写很多代码的时候,用上.h有很好的作用,这时候我们只要给对方公司*.h文件就行了,这样既提供了必要的信息,又保护了我们的核心代码。在.cpp中对.h文件进行..

小黄的博客 6172

C++头文件实现文件分别写什么

http://www.cnblogs.com/ider/archive/2011/06/30/what_is_in_cpp_header_and_implementation_file.html 在C++编程过程中,随着项目的越来越大,代码也会越来越多,并且难以管理和分析。于是,在C++中就要分出了头(.h)文件实现(.cpp)文件,并且也有了Package的概念。 对于以C起步

yarsen的专栏 4198

(C语言头文件实现的函数

在C语言里面,有时候为了方便(方便的同义词是偷懒),函数就直接在头文件里面实现了。那么这样子有什么问题呢?下面举个例子,这个例子只有3个文件/* fun.h */#ifndef FUN_H#define FUN_Hvoid base(){};void fun();#endif /* fun.c */#include "fun.h"void fun(){    base();}/* main.c *

jiangnanyouzi的专栏 1万+

C++头文件(.h文件实现文件(.cpp)应该怎么写比较规范?

C++中的.h文件.cpp 文件具体应该写什么

weixin_45914251的博客 1211

C:程序的分文件编写

C/C++文件编写代码

a287100886的博客 570

C++ 头文件的作用和用法

示例代码编译运行环境:Windows 64bits+VS2017+Debug+Win32。头文件是 C/C++ 程序不可或缺的组成部分,我们需要了解头文件的作用和相关规范。

Doublelv 的博客专栏。 4万+

编译器如何根据头文件来找到相应实现的cpp文件?

转自csdn的steedhorse回答: 编译器不管头文件的,头文件只是用来被cpp文件包含的,被包含之后,它就成了那个cpp文件的一部分了,而编译器只编译.cpp文件,不会去单独编译一个头文件的。编译器这样做之后,针对每个编译过的cpp文件生成一个obj文件。然后连接器把所有这些obj文件连接成一个程序,或能是exe或dll(或做成静态的lib)。如果在连接的过程中,有些实体(比如变...

weixin_30338481的博客 1941

C++中“头文件”和“源文件”介绍

一、C++ 编译模式 通常,在一个 C++ 程序中,只包含.cpp 文件和 .h 文件两类文件。其中,.cpp 文件被称作 C++文件,里面放的都是 C++ 的源代码;而 .h 文件则被称作 C++ 头文件,里面放的也是 C++ 的源代码。 C++ 语言支持"分别编译"(separate compilation)。也就是说,一个程序所有的内容,可以分成不同的部分分别放在不同的 .cpp 文件里。.cpp 文件里的东西都是相对独立的,在编译(compile)时不需要...

asdflucas的专栏 4784

C++头文件的作用以及用法

C++头文件的作用以及用法前言一、头文件的作用二、头文件的用法2.1头文件的内容2.2使用系统提供的头文件2.3避免头文件被重复包含参考文献 前言 头文件是C/C++程序不可缺少的组成部分,使用时,应该了解头文件的作用和相关规范。 一、头文件的作用 C/C++编译采用的是分离编译模式。在一个项目中,有多个源文件存在,但是它们总会有一些相同的内容,比如用户自定义类型、全局变量、全局函数的声明等。将这些内容抽取出来放到头文件中,提供给各个源文件包含,就可以避免想相同内容的重复书写,提高编程效率和代码安全性。所以

qq_40635314的博客 2万+

C++头文件的作用以及用法

头文件的作用:加强类型检查,提高类型安全性;减少公用代码的重复书写,提高编程效率;提供保密和代码重用的手段。

qq_41950508的博客 2575

C语言头文件实现内外接口隔离

C语言头文件实现内外接口隔离

qq_39030013的博客 1480

C语言自己编写头文件

C语言

u010783226的专栏 9768

c++ 头文件的作用

头文件 每个C++/C程序通常分为两个文件。一个文件用于保存程序的声明(declaration),称为头文件。另一个文件用于保存程序的实现(implementation),称为定义(definition)文件C++/C程序的头文件以“.h”为后缀,C程序的定义文件以“.c”为后缀,C++程序的定义文件通常以“.cpp”为后缀(也有一些系统以“.cc”或“.cxx”为后缀)。 1.1 版权...

keke_Xin的专栏 415
上一篇: c++ 小记1
下一篇: unity 特殊文件夹
Tonight_Alive
博客等级 码龄12年 16粉丝 20原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值