源文件和头文件

合集下载

CC++中的源文件与头文件的区别

CC++中的源文件与头文件的区别

CC++中的源⽂件与头⽂件的区别问题提出的背景:最近在⾃⼰动⼿,⽤C来实现各类经典算法,还搬到了Github上,但是有⼀个问题⽐较困扰我,就是这些可以复⽤的,作为⼯具⽅法的算法,究竟应该放在头⽂件还是源⽂件⾥?⼀般的、通⽤的准则到底是什么呢?或者说头⽂件与源⽂件的作⽤究竟是什么?在编译连接等过程中,编译器会对他们有怎样的区别对待呢?⼀、实现究竟放在哪⾥?⾸先回答第⼀个问题,⼀般来说,什么时候需要把实现放在头⽂件⾥,什么时候⼜需要把实现放在源⽂件⾥?(此部分参考:)不把实现放在头⽂件中,往往是出于以下⼏种顾虑:1、暴露了实现细节2、头⽂件被包含到不同的源⽂件中,会导致链接冲突3、头⽂件被包含到不同的源⽂件中,会导致有多份实现被编译出来,增⼤可执⾏体的体积如果有顾虑 1 ,那很显然应该在第⼀时间抛弃完全在头⽂件中实现的念头。

⾄于顾虑 2和3 的,我们举例如下。

例如有以下头⽂件 c_function.h:int integer_add(const int a, const int b){return a + b;}如果在同⼀⼯程中,有 a.c 和 b.c 两个(或两个以上)源⽂件包含了此头⽂件,则在链接时期就会发⽣冲突,因为在两个源⽂件编译得到的⽬标⽂件中都有⼀份 integer_add 的函数实现,导致链接器不知道对于调⽤了此函数的调⽤者,应该使⽤哪⼀个副本。

解决冲突办法有两个,⼀个是加上 inline ,另⼀个是加上 static 。

使⽤这两个关键字的任意⼀个来修饰 integer_add 函数,然⽽本质却⼤不相同。

如果使⽤ inline ,则意味着编译器会在调⽤此函数的地⽅把函数的⽬标代码直接插⼊,⽽不是放置⼀个真正的函数调⽤,实际作⽤就是这个函数事实上已经不再存在,⽽是像宏⼀样被就地展开了。

使⽤ inline 的副作⽤,⾸先在于⽏庸置疑地,代码的体积变⼤了;其次则是,这个关键字严格算起来并不是 C 语⾔的关键字,使⽤它多少会带来⼀些移植性⽅⾯的风险。

c++编译顺序

c++编译顺序

c++编译顺序c++编译顺序是指c++程序从源代码到可执行文件的转换过程中,各个源文件和目标文件的生成和处理的先后顺序。

c++程序一般由多个源文件(.cpp)和头文件(.h)组成,每个源文件都需要经过预处理(preprocess),编译(compile),汇编(assemble)和链接(link)四个阶段,才能最终生成可执行文件(.exe)。

不同的源文件之间可能存在依赖关系,比如一个源文件调用了另一个源文件中定义的函数或变量,或者一个源文件包含了另一个头文件中声明的内容。

因此,c++编译顺序需要考虑这些依赖关系,保证每个源文件在被处理之前,它所依赖的其他源文件或头文件已经被正确地处理过。

原理c++编译是基于c++程序的运行原理和编译器的工作原理。

c++程序的运行原理是基于计算机硬件和操作系统的,计算机只能执行机器语言指令,而操作系统负责加载可执行文件到内存,并调用入口函数开始执行。

因此,c++程序需要将人类可读的高级语言代码转换为机器可执行的二进制代码,并且按照操作系统规定的格式组织成可执行文件。

这个转换过程就是由编译器完成的。

编译器是一种软件,它可以将一种语言(源语言)翻译成另一种语言(目标语言)。

为了提高翻译效率和质量,编译器一般分为多个模块,每个模块负责完成一部分翻译工作,并生成中间结果。

这些中间结果可以是文本文件,也可以是二进制文件。

最后一个模块负责将所有中间结果合并成最终结果。

这些模块之间也有依赖关系,后面的模块需要使用前面模块生成的中间结果作为输入。

步骤c++编译可以分为四个阶段:预处理(preprocess),编译(compile),汇编(assemble)和链接(link)。

每个阶段都会生成对应的中间结果,并且有自己的工作内容和注意事项。

下面分别介绍每个阶段的具体内容。

预处理预处理是指对源代码进行一些文本替换和拷贝操作,以便于后续阶段进行语法分析和翻译。

预处理主要完成以下工作:-处理预处理指令(preprocessor directive),即以#开头的指令,比如#include, #define, #ifdef, #endif等。

C++中头文件(.h)和源文件(.cpp)都应该写些什么

C++中头文件(.h)和源文件(.cpp)都应该写些什么

C++中头⽂件(.h)和源⽂件(.cpp)都应该写些什么头⽂件(.h):写类的声明(包括类⾥⾯的成员和⽅法的声明)、函数原型、#define常数等,但⼀般来说不写出具体的实现。

在写头⽂件时需要注意,在开头和结尾处必须按照如下样式加上预编译语句(如下):#ifndef CIRCLE_H#define CIRCLE_H//你的代码写在这⾥#endif这样做是为了防⽌重复编译,不这样做就有可能出错。

⾄于CIRCLE_H这个名字实际上是⽆所谓的,你叫什么都⾏,只要符合规范都⾏。

原则上来说,⾮常建议把它写成这种形式,因为⽐较容易和头⽂件的名字对应。

源⽂件(.cpp):源⽂件主要写实现头⽂件中已经声明的那些函数的具体代码。

需要注意的是,开头必须#include⼀下实现的头⽂件,以及要⽤到的头⽂件。

那么当你需要⽤到⾃⼰写的头⽂件中的类时,只需要#include进来就⾏了。

下⾯举个最简单的例⼦来描述⼀下,咱就求个圆⾯积。

第1步,建⽴⼀个空⼯程(以在VS2003环境下为例)。

第2步,在头⽂件的⽂件夹⾥新建⼀个名为Circle.h的头⽂件,它的内容如下:#ifndef CIRCLE_H#define CIRCLE_Hclass Circle{private:double r;//半径public:Circle();//构造函数Circle(double R);//构造函数double Area();//求⾯积函数};#endif注意到开头结尾的预编译语句。

在头⽂件⾥,并不写出函数的具体实现。

第3步,要给出Circle类的具体实现,因此,在源⽂件夹⾥新建⼀个Circle.cpp的⽂件,它的内容如下:#include "Circle.h"Circle::Circle(){this->r=5.0;}Circle::Circle(double R){this->r=R;}double Circle:: Area(){return 3.14*r*r;}需要注意的是:开头处包含了Circle.h,事实上,只要此cpp⽂件⽤到的⽂件,都要包含进来!这个⽂件的名字其实不⼀定要叫Circle.cpp,但⾮常建议cpp⽂件与头⽂件相对应。

C语言头文件源文件

C语言头文件源文件

C语⾔头⽂件源⽂件C语⾔头⽂件源⽂件1、头⽂件与源⽂件头⽂件⽤于声明接⼝函数,格式如下如创建test.h#ifndef _TEST_H_#define _TEST_H_/*接⼝函数的申明*/#endif#ifndef _TEST_H_#define _TEST_Hint sum(int x, int y);void swap(int *x, int *y);int max(int x, int y);#endif源⽂件⽤于接⼝函数的实现,源⽂件中只写接⼝函数的实现不能写main()函数#include <stdio.h>#include "test.h"int sum(int x, int y){return x+y;}void swap(int *x, int *y){int tmp;tmp = *x;*x = *y;*y = tmp;}int max(int x, int y){return (x>y)? x : y;}2、⽤户⽂件头⽂件和源⽂件⼀般是标准库⽂件或者⾃定义的库⽂件,⽤户⽂件则是我们⾃⼰写的⽂件,我们需要在⽤户⽂件中使⽤库⽂件或函数,就要包含所需的头⽂件#include <stdio.h>#include "test.h"int main(){int a = 1, b = 2;swap(&a, &b);printf("sum(%d,%d)=%d\n", a, b, sum(a, b));printf("a=%d, b=%d\n", a, b);printf("max(%d,%d)=%d\n", a, b, max(a, b));return0;}3、多⽂件编译当我们使⽤的时候,如果只编译main.c(gcc main.c)就会报错原因是在test.h中找不到函数的实现,所以在编译时要将源⽂件test.c和main.c⼀起编译(gcc main.c test.c),这样就不会报错4、makefile和shell脚本当我们包含的头⽂件特别多,在编译时就要编译很多源⽂件(gcc main.c test1.c test2.c test3.c test4.c ... testn.c),这样就会⾮常长,所以我们可以将命令⾏写到脚本⾥⾯进⾏批处理(1)shell脚本创建⼀个build.sh的脚本⽂件,然后将需要编译的命令⾏写到脚本⽂件⾥,编译时输⼊命令 sh build.sh就完成了编译(2)makefile(待续。

VS2008教程

VS2008教程

for(;;) {
pos1 = pos2 = 0;
if((pos1 = tmpstr.find_first_not_of(delimiters, pos2))
== string::npos)
break;
if((pos2 = tmpstr.find_first_of(delimiters, pos1))
}
return fields.size();
}
函数声明可以放在任何一个调用它的函数之前,而且在调用一个函数之前必须在调用者函数之前定义或声明被调函数。函数的定义只能有一次,如果调用者与被调用者不在同一编译单元,只能在调用者之前添加函数的声明。函数定义只能有一次,函数声明可以有无限次(理论上),这也是头文件的作用,将一批函数的声明放入一个头文件中,在任何需要这些函数声明的地方引用该头文件,以便于维护。
1.1.1.4. 小结
从理论上讲,声明与定义的区别就是:定义描述了内部内容,而声明不表露内部内容,只说明对外接口。例如,类的定义包含了内部成员的声明,而类的声明不包含任何类的内部细节;函数的定义包含了函数体,而函数声明只包括函数的签名;变量的定义可以包含初始化,而变量的声明不可以包含初始化。
class B { public: A* CreateA( void ) const; }
类的定义只给出了类包含了哪些数据(成员变量)和接口(成员函数),但并没有给出实现,程序的实现应该放在原代码文件中。如例程[2-1]中的Point类定义在Point.hpp头文件中,相应的源代码文件Point.cpp的内容如例程[2-4]所示。
// 例程2-2: 类的声明
class Point;
类的说明与实现都可以放在头文件中,因为上层代码需要使用Point的类必须知道当前工程已经定义了这个类。但应该使用定义还是声明呢?使用声明可以的地方使用定义都是可以的,但是,过多得使用定义会使项目编译时间加长,减慢编译速度,细节可参见(@see effective series,item 34)。

c语言中头文件和源文件解析 编译原理

c语言中头文件和源文件解析 编译原理

c语言中头文件和源文件解析编译原理头文件和源文件是C语言中常见的两种文件类型,它们在编译原理中扮演着重要的角色。

本文将对头文件和源文件进行解析,从编译原理的角度探讨它们的作用和使用方法。

一、头文件的概念和作用头文件是一种特殊的文件,它通常以.h作为文件扩展名,用于存放函数声明、宏定义、结构体声明等内容。

头文件的作用主要有以下几个方面:1.1 提供接口声明头文件中包含了函数的声明,通过包含头文件可以让源文件知道这些函数的存在,并且能够正确地调用这些函数。

这种方式可以提高代码的可读性和可维护性,使得不同的源文件可以共享同一个函数的实现。

1.2 定义常量和宏头文件中可以定义常量和宏,这些常量和宏可以被多个源文件引用和使用。

通过在头文件中定义常量和宏,可以提高代码的可重用性和可维护性,避免了在多个源文件中重复定义常量和宏的问题。

1.3 声明结构体和类型头文件中可以声明结构体和类型,这些结构体和类型可以被多个源文件引用和使用。

通过在头文件中声明结构体和类型,可以提高代码的可读性和可维护性,避免了在多个源文件中重复声明结构体和类型的问题。

二、源文件的概念和作用源文件是C语言程序的主要组成部分,它通常以.c作为文件扩展名,包含了具体的函数实现和全局变量定义等内容。

源文件的作用主要有以下几个方面:2.1 实现函数的定义源文件中包含了函数的具体实现,通过编译和链接的过程,可以将函数的定义和函数的调用联系起来。

源文件中的函数实现可以直接访问和修改全局变量,同时也可以调用其他源文件中的函数。

2.2 定义全局变量源文件中可以定义全局变量,这些全局变量可以被多个函数访问和修改。

全局变量在程序的整个执行过程中都是存在的,它们的作用域不限于某个函数,可以在不同的函数之间共享数据。

2.3 包含头文件源文件可以通过包含头文件来使用头文件中定义的函数、常量、宏、结构体和类型等。

通过包含头文件,源文件可以获取到头文件中的声明信息,从而可以正确地使用其中定义的内容。

头文件与源文件在c语言中应用简单示例

头文件与源文件在c语言中应用简单示例

一、概述C语言作为一种被广泛使用的程序设计语言,其核心概念之一就是头文件(Header File)和源文件(Source File)。

头文件和源文件在C 语言中的应用非常普遍,它们的合理使用对于提高代码的可读性、可维护性和可重用性,起着非常重要的作用。

本文将从头文件和源文件的概念入手,通过简单的示例帮助读者更加深入的理解并应用头文件与源文件在C语言中的重要性和用法。

二、头文件与源文件概念与作用1. 头文件(Header File)是一种特殊的文本文件,它以“.h”为扩展名,用来包含要被其他文件引用的声明和定义,通常包含函数原型、宏定义、数据结构等内容。

当程序需要使用某些外部的函数或数据结构时,可以通过#include指令引用相应的头文件。

2. 源文件(Source File)是包含C语言源代码的文件,通常以“.c”为扩展名。

源文件包含了程序的实际代码,其中定义了各种函数、变量、数据结构等。

源文件中也可以通过#include指令引用头文件,以便在源文件中使用头文件中声明的函数和数据结构。

三、头文件的编写与应用1. 定义头文件的格式头文件通常包括以下内容:- 头文件保护宏(Header Guard):用来防止头文件被多次引用的问题,通常采用#ifndef、#define和#endif三个宏来实现;- 函数原型:声明函数的名称、返回类型和参数列表,以便在源文件中使用;- 宏定义:定义一些常量和宏,方便程序中的代码使用。

2. 编写简单的头文件示例以一个简单的数学计算为例,定义一个头文件math.h包含两个函数的声明:```c#ifndef MATH_H#define MATH_Hint add(int a, int b);int subtract(int a, int b);#endif```3. 应用头文件在源文件中使用这个头文件:```c#include "math.h"int m本人n() {int result1 = add(10, 5);int result2 = subtract(10, 5);// other code...return 0;}```四、源文件的编写与应用1. 定义源文件的格式源文件中包括了实际的函数定义和全局变量定义,以及程序的入口函数m本人n()定义。

C源文件要包含自己的头文件

C源文件要包含自己的头文件

引言:我们经常在c工程中发现,源文件中要包含自己的头文件。

一直以来,都不知道为什么这样做。

现在,我知道了。

以前的认知:我认为,.c文件没有必要包含自己的.h文件。

.h文件包含.c文件中定义的函数和全局变量的声明,.h文件就是.c文件提供的对外接口文件。

既然.h文件就是.c文件提供的对外接口文件,那么.c文件就没必要包含自己的.h文件了(.h文件是对外提供用的,对内又何必再包含进来呢)。

鉴于这样的理解,我对于工程中.c源文件包含自己的.h头文件很是不理解,不知道为什么要这样做。

现在对此的理解:但是现在,我知道为什么要源文件包含自己的头文件了。

如下,一段书中的原话:“如果希望让编译器检查声明的一致性, 一定要把全局声明放到头文件中。

特别是, 永远不要把外部函数的原型(也就是函数声明)放到.c 文件中: 通常它与定义的一致性不能得到检查, 而矛盾的原型(也就是函数声明)比不用还糟糕。

”注意:外部函数的原型,就是外部函数的声明。

对这段话的理解:为什么:“永远不要把外部函数的原型放到.c 文件中”这个外部函数A指的是B.c文件之外定义的函数,B.c文件中需要使用外部函数A,就需要先对外部函数A声明(对外部函数的声明就是外部函数原型)。

对这个外部函数A的声明,不能放在B.c文件里面来实现。

以实例说明:①假若工程中有2个源文件a.c和b.c;a.c的头文件为a.h,b.c的头文件为b.h。

②a.c中定义了一个函数sum。

③b.c要引用sum 这个函数。

做法是:在b.c中声明sum这个函数。

然后b.c就可以使用sum函数了。

这样的做法就是把外部函数sum的声明放到了b.c中来。

然而,这样的做法很不妥。

不妥的原因:sum是在a.c中定义的,而声明确是在b.c中,sum函数的定义和声明不是在同一个文件中的。

定义和声明不在同一个文件中,编译的时候,编译器就不能对定义和声明的一致性进行检查。

这样,如果sum的定义和声明不一致,编译器就无法检查出来(定义和声明不在同一个文件中),那么编译的时候不会报错,但是程序运行的时候就可能会出错。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

c语言笔记--头文件和源文件的区别
关于头文件和源文件的分别
首先,我们可以将所有东西都放在一个.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,外部链接(这个是默认情况),那么根据在同一个程序内不可出现
同名函数的要求,连接器会毫不留情给你一个连接错误!
;。

相关文档
最新文档