当前位置:文档之家› C++中头文件相互包含的几点问题

C++中头文件相互包含的几点问题

C++中头文件相互包含的几点问题
C++中头文件相互包含的几点问题

C++中头文件相互包含的几点问题

一、类嵌套的疑问

C++头文件重复包含实在是一个令人头痛的问题,前一段时间在做一个简单的数据结构演示程序的时候,不只一次的遇到这种问题。假设我们有两个类A和B,分别定义在各自的有文件A.h和B.h 中,但是在A中要用到B,B中也要用到A,但是这样的写法当然是错误的:

class B;

class A

{

public:

B b;

};

class B

{

public:

A a;

};

因为在A对象中要开辟一块属于B的空间,而B中又有A的空间,是一个逻辑错误,无法实现的。在这里我们只需要把其中的一个A类中的B类型成员改成指针形式就可以避免这个无限延伸的怪圈了。为什么要更改A而不是B?因为就算你在B中做了类似的动作,也仍然会编译错误,表面上这仅仅上一个先后顺序的问题。

为什么会这样呢?因为C++编译器自上而下编译源文件的时候,对每一个数据的定义,总是需要知道定义的数据的类型的大小。在预先声明语句class B;之后,编译器已经知道B是一个类,但是其中的数据却是未知的,因此B类型的大小也不知道。这样就造成了编译失败,VC++6.0下会得到如下编译错误:

error C2079: 'b' uses undefined class 'B'

将A中的b更改为B指针类型之后,由于在特定的平台上,指针所占的空间是一定的(在Win32平台上是4字节),这样可以通过编译。

二、不同头文件中的类的嵌套

在实际编程中,不同的类一般是放在不同的相互独立的头文件中的,这样两个类在相互引用时又会有不一样的问题。重复编译是问题出现的根本原因。为了保证头文件仅被编译一次,在C++中常用的办法是使用条件编译命令。在头文件中我们常常会看到以下语句段(以VC++6.0自动生成的头文件为例):

#if !defined(AFX_STACK_H__1F725F28_AF9E_4BEB_8560_67813900AE6B__INCLUDE D_)

#define AFX_STACK_H__1F725F28_AF9E_4BEB_8560_67813900AE6B__INCLUDED_ //很多语句……

#endif

其中首句#if !defined也经常做#ifndef,作用相同。意思是如果没有定义过这个宏,那么就定义它,然后执行直到#endif的所有语句。如果下次在与要这段代码,由于已经定义了那个宏,因此重复的代码不会被再次执行。这实在是一个巧妙而高效的办法。在高版本的VC++上,还可以使用这个命令来代替以上的所有:

#pragma once

它的意思是,本文件内的代码只被使用一次。

但是不要以为使用了这种机制就全部搞定了,比如在以下的代码中:

//文件A.h中的代码

#pragma once

#include "B.h"

class A

{

public:

B* b;

};

//文件B.h中的代码

#pragma once

#include "A.h"

class B

{

public:

A* a;

};

这里两者都使用了指针成员,因此嵌套本身不会有什么问题,在主函数前面使用#include "A.h"之后,主要编译错误如下:

error C2501: 'A' : missing storage-class or type specifiers

仍然是类型不能找到的错误。其实这里仍然需要前置声明。分别添加前置声明之后,可以成功编译了。代码形式如下:

//文件A.h中的代码

#pragma once

#include "B.h"

class B;

class A

{

public:

B* b;

};

//文件B.h中的代码

#pragma once

#include "A.h"

class B;

class B

{

public:

A* a;

};

这样至少可以说明,头文件包含代替不了前置声明。有的时候只能依靠前置声明来解决问题。我们还

要思考一下,有了前置声明的时候头文件包含还是必要的吗?我们尝试去掉 A.h和 B.h中的#include行,发现没有出现新的错误。那么究竟什么时候需要前置声明,什么时候需要头文件包含呢?

三、两点原则

头文件包含其实是一想很烦琐的工作,不但我们看着累,编译器编译的时候也很累,再加上头文件中常常出现的宏定义。感觉各种宏定义的展开是非常耗时间的,远不如自定义函数来得速度。我仅就不同头文件、源文件间的句则结构问题提出两点原则,仅供参考:

第一个原则应该是,如果可以不包含头文件,那就不要包含了。这时候前置声明可以解决问题。如果使用的仅仅是一个类的指针,没有使用这个类的具体对象(非指针),也没有访问到类的具体成员,那么前置声明就可以了。因为指针这一数据类型的大小是特定的,编译器可以获知。

第二个原则应该是,尽量在CPP文件中包含头文件,而非在头文件中。假设类A的一个成员是是一个指向类B的指针,在类A的头文件中使用了类B的前置声明并便宜成功,那么在A的实现中我们需要访问B的具体成员,因此需要包含头文件,那么我们应该在类A的实现部分(CPP文件)包含类B的头文件而非声明部分(H文件)。

防止变量重复定义、头文件重复包含、嵌套包含

【转载】防止变量重复定义、头文件重复包含、嵌套包含 【转 自】 https://www.doczj.com/doc/2c11483466.html,/zengzhaonong/blog/item/8a8871062d481f7f03 088106.html #include文件的一个不利之处在于一个头文件可能会被多次包含,为了说明这种错误,考虑下面的代码: #include "x.h" #include "x.h" 显然,这里文件x.h被包含了两次,没有人会故意编写这样的代码。但是下面的代码: #include "a.h" #include "b.h" 看上去没什么问题。如果a.h和b.h都包含了一个头文件x.h。那么x.h在此也同样被包含了两次,只不过它的形式不是那么明显而已。 多重包含在绝大多数情况下出现在大型程序中,它往往需要使用很多头文件,因此要发现重复包含并不容易。要解决这个问题,我们可以使用条件编译。如果所有的头文件都像下面这样编写: #ifndef _HEADERNAME_H

#define _HEADERNAME_H ...//(头文件内容) #endif 那么多重包含的危险就被消除了。当头文件第一次被包含时,它被正常处理,符号_HEADERNAME_H被定义为1。如果头文件被再次包含,通过条件编译,它的内容被忽略。符号_HEADERNAME_H按照被包含头文件的文件名进行取名,以避免由于其他头文件使用相同的符号而引起的冲突。 但是,你必须记住预处理器仍将整个头文件读入,即使这个头文件所有内容将被忽略。由于这种处理将托慢编译速度,所以如果可能,应该避免出现多重包含。test-1.0使用#ifndef只是防止了头文件被重复包含(其实本例中只 有一个头件,不会存在重复包含的问题),但是无法防止变量被重复定义。 # vi test.c ------------------------------- #include

C语言文件包含与头文件写法

文件包含与头文件的写法 很多人对C语言中的“文件包含”都不陌生了,文件包含处理在程序开发中会给我们的模块化程序设计带来很大的好处,通过文件包含的方法把程序中的各个功能模块联系起来是模块化程序设计中的一种非常有利的手段。 文件包含处理是指在一个源文件中,通过文件包含命令将另一个源文件的内容全部包含在此文件中。在源文件编译时,连同被包含进来的文件一同编译,生成目标目标文件。 很多人再初学时都会对这个很晕,怎么写文件件? 怎么包含才能避免重定义? 等等问题。。。 其实这个只要了解了文件包含的基本处理方法就可以对文件包含有一个很好的理解与应用了,下来我们一起来看一下: 文件包含的处理方法: 首先大家需要清楚: (1) 处理时间:文件包含也是以"#"开头来写的(#include ), 那么它就是写给预处理器来看了, 也就是说文件包含是会在编译预处理阶段进行处理的。 (2) 处理方法:在预处理阶段,系统自动对#include命令进行处理,具体做法是:降包含文件的内容复制到包含语句(#include )处,得到新的文件,然后再对这个新的文件进行编译。抓住这两点,那么这个东东就没有什么难的了。。。 一般情况下文件包含分为两种:包含.h文件和包含.c文件 1. 当然对于这两情况也都是按照上面说的方法来处理的。呵呵,这个肯定是没得说的. 2. 包含.c文件和编译多文件程序是不同的。 多文件程序: 是在源文件编译时把多个文件进行编译、连接在一起生成一个可执行文件。包含.c文件:按照我们上边的说法则是把多个文件合并为一个文件进行编译。 接下来通过例子看一下: (1)包含.c文件: 1://file1: main.c 2: #include 3: #include "fun.c" 4:int main() 5: { 6:int a=5,b=19; 7: c = a; 8:sun(a,b); 9:printf("c=%d\n",c); 10:return 0; 11: } 12: //end of file1

C++中头文件相互包含的几点问题

C++中头文件相互包含的几点问题 一、类嵌套的疑问 C++头文件重复包含实在是一个令人头痛的问题,前一段时间在做一个简单的数据结构演示程序的时候,不只一次的遇到这种问题。假设我们有两个类A和B,分别定义在各自的有文件A.h和B.h 中,但是在A中要用到B,B中也要用到A,但是这样的写法当然是错误的: class B; class A { public: B b; }; class B { public: A a; }; 因为在A对象中要开辟一块属于B的空间,而B中又有A的空间,是一个逻辑错误,无法实现的。在这里我们只需要把其中的一个A类中的B类型成员改成指针形式就可以避免这个无限延伸的怪圈了。为什么要更改A而不是B?因为就算你在B中做了类似的动作,也仍然会编译错误,表面上这仅仅上一个先后顺序的问题。 为什么会这样呢?因为C++编译器自上而下编译源文件的时候,对每一个数据的定义,总是需要知道定义的数据的类型的大小。在预先声明语句class B;之后,编译器已经知道B是一个类,但是其中的数据却是未知的,因此B类型的大小也不知道。这样就造成了编译失败,VC++6.0下会得到如下编译错误: error C2079: 'b' uses undefined class 'B' 将A中的b更改为B指针类型之后,由于在特定的平台上,指针所占的空间是一定的(在Win32平台上是4字节),这样可以通过编译。 二、不同头文件中的类的嵌套

在实际编程中,不同的类一般是放在不同的相互独立的头文件中的,这样两个类在相互引用时又会有不一样的问题。重复编译是问题出现的根本原因。为了保证头文件仅被编译一次,在C++中常用的办法是使用条件编译命令。在头文件中我们常常会看到以下语句段(以VC++6.0自动生成的头文件为例): #if !defined(AFX_STACK_H__1F725F28_AF9E_4BEB_8560_67813900AE6B__INCLUDE D_) #define AFX_STACK_H__1F725F28_AF9E_4BEB_8560_67813900AE6B__INCLUDED_ //很多语句…… #endif 其中首句#if !defined也经常做#ifndef,作用相同。意思是如果没有定义过这个宏,那么就定义它,然后执行直到#endif的所有语句。如果下次在与要这段代码,由于已经定义了那个宏,因此重复的代码不会被再次执行。这实在是一个巧妙而高效的办法。在高版本的VC++上,还可以使用这个命令来代替以上的所有: #pragma once 它的意思是,本文件内的代码只被使用一次。 但是不要以为使用了这种机制就全部搞定了,比如在以下的代码中: //文件A.h中的代码 #pragma once #include "B.h" class A { public: B* b; }; //文件B.h中的代码 #pragma once #include "A.h" class B

C语言中,头文件和源文件的关系

C语言中,头文件和源文件的关系(转) 简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程: 1.预处理阶段 2.词法与语法分析阶段 3.编译阶段,首先编译成纯汇编语句,再将之汇编成跟CPU相关的二进制码,生成各个目标文件(.obj文件) 4.连接阶段,将各个目标文件中的各段代码进行绝对地址定位,生成跟特定平台相关的可执行文件,当然,最后还可以用objcopy生成纯二进制码,也就是去掉了文件格式信息。(生成.exe文件) 编译器在编译时是以C文件为单位进行的,也就是说如果你的项目中一个C文件都没有,那么你的项目将无法编译,连接器是以目标文件为单位,它将一个或多个目标文件进行函数与变量的重定位,生成最终的可执行文件,在PC上的程序开发,一般都有一个main函数,这是各个编译器的约定,当然,你如果自己写连接器脚本的话,可以不用main函数作为程序入口!!!! (main .c文件目标文件可执行文件) 有了这些基础知识,再言归正传,为了生成一个最终的可执行文件,就需要一些目标文件,也就是需要C文件,而这些C文件中又需要一个main 函数作为可执行程序的入口,那么我们就从一个C文件入手,假定这个C文件内容如下: #include #include "mytest.h" int main(int argc,char **argv) { test = 25; printf("test.................%d/n",test); } 头文件内容如下: 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文件中同样存在相同变量名的拷贝,关键是此变量被

头文件包含问题

头文件包含问题 C++中基础类互相引用带来的问题 在一些大的工程中,可能会包含几十个基础类,免不了之间会互相引用( 不满足继承关系,而是组合关系) 。也就是需要互相声明。好了,这时候会带来一些混乱。如果处理得不好,会搞得一团糟,根据我的经验,简单谈谈自已的处理办法: 编码时,我们一般会尽量避免include 头文件,而是采用声明class XXX 。但有时候还是必须用Include 头文件,那么,两者的划分在于什么呢? 应该是很明确的,但书上好像都少有提及。 首先: 我们要明白为什么要用声明取代头文件包含:对了,是为了避免无必要的重编译( 在头文件发生变更时) 。工程较大,低速机,或基础类经常变更( 不合理的设计吧) ,编译速度还是会在意的,另外,更为重要的是,采用声明可降低代码(class) 之间的藕合度,这也是面向对象设计的一大原则。 二:一般原则: a. 头文件中尽量少include, 如果可以简单申明class clsOld; 解决,那最好。减少没有必要的include; b. 实现文件中也要尽量少include, 不要include 没有用到的头文件。 三:那什么时候可以只是简单声明class clsOld 呢? 简单的说:不需要知道clsOld 的内存布局的用法都可以( 静态成员除外) ,也就是讲如果是指针或引用方式的都行。 比如: clsOld * m_pOld; // 指针占4 个字节长

clsOld & test(clsOld * pOld) {return *pOld}; 一切OK 。 四:什么时候不能简单声明class clsOld ,必须include 呢? 不满足三的情况下: 比如: clsOld m_Objold; // 不知道占据大小,必须要通过它的具体声明来计算 原因很简单,想想你要计算sizeof(classNew) ,但连clsOld 的size 都不知道,编译器显然会无能为力。 特殊情况: int test() { return clsOld::m_sInt;} 静态成员调用,想来应该是不需要知道内存布局的,但因为需要知道m_sInt 是属于clsOld 命名空间的,如果只声明class xxx 显然是不足以说明的,所以必须包含头文件。 综上所述,我有以下几点建议: 1 :如果有共同相关依赖( 必须include) 的类,比如A,B 都依赖D 可以放在一起,然后直接Include "d" 类的使用者只需关心与本类暴露出的相关类型,内部用到的类型不用去管( 不用自已去include d) 。这样给出的class ,调用者才更好用( 不用去看代码查找,是不是还需要包含其它头文件) 。 2 :如果A 类依赖D B 类不依赖D ,可以把它们分开两个头文件。各自Incl ude 。这样可避免当D 发生变化时,避免不必要重编译。 3 :类中尽量采用指针或引用方式调用其它类,这样就可以只声明class xxx 了。并且这也符合资源最优利用,更利于使用多态。

头文件如何写

C程序采用模块化的编程思想,需合理地将一个很大的软件划分为一系列功能独立的部分合作完成系统的需求,在模块的划分上主要依据功能。模块由头文件和实现文件组成,对头文件和实现文件的正确使用方法是: 规则1头文件(.h)中是对于该模块接口的声明,接口包括该模块提供给其它模块调用的外部函数及外部全局变量,对这些变量和函数都需在.h中文件中冠以extern关键字声明; 规则2 模块内的函数和全局变量需在.c文件开头冠以static关键字声明; 规则3 永远不要在.h文件中定义变量; 许多程序员对定义变量和声明变量混淆不清,定义变量和声明变量的区别在于定义会产生内存分配的操作,是汇编阶段的概念;而声明则只是告诉包含该声明的模块在连接阶段从其它模块寻找外部函数和变量。 规则4 如果要用其它模块定义的变量和函数,直接包含其头文件即可。 许多程序员喜欢这样做,当他们要访问其它模块定义的变量时,他们在本模块文件开头添加这样的语句:extern int externVar; 抛弃这种做法吧,只要头文件按规则1完成,某模块要访问其它模块中定义的全局变量时,只要包含该模块的头文件即可。 共享变量声明 就像在函数间共享变量的方式一样,变量可以在文件中共享。为了共享函数,要把函数的定义放在一个源文件中,然后在需要调用此函数的其他文件中放置声明。共享变量的方法和此方式非常类似。在此之前,不需要区别变量的声明和它的定义。为了声明变量i,写成如下形式:int i; 这样不仅声明i是int型的变量,而且也对i进行了定义,从而使编译器为i留出了空间。为了声明没有定义的变量i,需要在变量声明的开始处放置关键字extern:extern int i; extern提示编译器变量i是在程序中的其他位置定义的(大多数可能是在不同的源文件中),因此不需要为i分配空间。 顺便说一句,extern可以用于所有类型的变量。在数组的声明中使用extern时,可以忽略数组的长度:extern int a[];因为此刻编译器不用为数组a分配空间,所以也就不需要知道数组a的长度了。 为了在几个源文件中共享变量i,首先把变量i的定义放置在一个文件中:int i;如果需要对变量i初始化,那么可以在这里放初始值。在编译这个文件时,编译器将会为变量i分配内存空间,而其他文件将包含变量i的声明:extern int i;通过在每个文件中声明变量i,使得在这些文件中可以访问/或修改变量i。然而,由于关键字extern,使得编译器不会在每次编译其中某个文件时为变量i分配额外的内存空间。 当在文件中共享变量时,会面临和共享函数时相似的挑战:确保变量的所有声明和变量的定义一致。 为了避免矛盾,通常把共享变量的声明放置在头文件中。需要访问特殊变量的源文件可以稍后包含适当的头文件。此外,含有变量定义的源文件包含每一个含有变量声明的头文件,这样使编译器可以检查两者是否匹配。 如果工程很大,头文件很多,而有几个头文件又是经常要用的,那么 1。把这些头文件全部写到一个头文件里面去,比如写到preh.h 2。写一个preh.c,里面只一句话:#include "preh.h" 3。对于preh.c,在project setting里面设置creat precompiled headers,对于其他c文件,设置use precompiled header file

C语言中头文件包含的意义

C语言中头文件包含的意义 在C/C++中,经常会在一个文件中包含其它文件。例如: #include 还有一个概念。两个文件,分别为A和B。B中定义了一个变量var,A包含B,在A中就可以访问变量var。我经常将包含文件,与访问权限混淆。之前我一直以为只有包含了文件,才可以访问文件下面的变量。其实不是。我将概念逐个梳理一遍,就会明白它们的区别了。 首先:文件包含的意思是什么呢?例如文件A包含文件B,意思是A将文件B的所有内容拷贝过来,放到A的前面,与文件A的其它内容一起,作为文件A。一句话,就是合并两个文件。文件包含其实就简单的拷贝。如果还有一个文件叫C,文件B包含文件C,文件A 也包含文件C。这个时候,C在A中就会有两份拷贝。这没有问题,只是内容重复而已。但是会导致空间的浪费,以及时间的浪费。所以,很多时候,都会在头文件中使用下面的预定义语句来避免文件的重复拷贝。 #ifndef _HEADER_FILEA_ #define _HEADER_FILEA_ //头文件的代码 .... #endif。 其次:有一种变量叫做全局变量,在函数外面声明或者定义的变量都是全局变量。不管是什么文件,也不管在文件的什么位置声明或者定义,只要是在函数外面,并且非const变量,就是全局变量。全局变量的意思是:整个程序都可以访问它。不需要包含该变量所在的文件。既然在整个程序中都可以访问全局变量,那么为什么我们还要包含头文件呢?因为在C++中,只有变量声明或者定义之后,才可以访问一个变量。我们可以在使用变量之前的位置声明变量,不需要包含变量所在的文件,就可以访问变量了(当然,这个变量指的是全局变量)。但是,当一个文件A中声明了很多变量的时候,而文件B又要访问A中很多变量,就要在B中声明所有需要访问的变量。这样会非常麻烦。所以,我们通常都是包含文件,而不是一个个的声明。但是包含文件,又会出现问题。 在介绍这个问题之前,我再说一个概念。变量可以多次声明,但是不能重复定义,变量在整个程序中只能定义一次。现在回归到问题。举例,两个文件,一个A,一个B,A包含B。前面说过了文件包含的意义,是简单地拷贝所有的内容,即将文件合并。 如果在B中定义了变量int iFirst =10; A包含B,那么A中也会有这个定义语句。iFirst在A和B中都定义了,即重复定义。这违反了变量不能重复定义的原则。怎么办?我们想包含整个文件,不用一个一个地声明变量,可是包含整个文件,又会出现重复定义的问题。所以,高手发明了一种东西叫做头文件。在头文件中,仅仅声明所有变量,但是不定义它们。将变量的定义放到一个实现文件里面。为了统一,头文件以.h作为后缀名,实现文件以.c或者.cpp作为后缀名。将变量的声明放到头文件.h中,将变量的定义放到.c或者.cpp文件中。这样就可以完美地解决这个矛盾了。既包含文件,又不会出现重复定义的问题。说到这里,我们又有疑问了。我们只包含头文件A.h,但是变量都定义在A.cpp文件中,我们怎么可以访问那些变量啊?说了这么多,又忘记了文章刚开始说的全局变量的意思了。这里再次强调:

C++头文件大全

C/C++头文件一览 C、传统C++ #include //设定插入点 使用断言 assert()宏是用于保证满足某个特定条件,用法是: assert(表达式); 如果表达式的值为假,整个程序将退出,并输出一条错误信息。如果表达式的值为真则继续执行后面的语句。 使用这个宏前需要包含头文件assert.h 例如 #include #include void main() { float a,b; scan("%f %f",&a,&b); assert(b!=0); printf("%f\n",a/b); } 以上的程序要计算A/B的值,因此要求b!=0,所以在程序中使用了assert()用于确保b!=0,如果 b==0,则程序会退出。 #include //字符处理 isalnum 判断一个字符是否是字符类的数字或者字母 isalpha 判断一个字符是否是字母 isblank 判断一个字符是空白字符(空格和水平制表符Tab) iscntrl 判断一个控制符(ascii码0-31之间的字符) isdigit 判断一个字符是否是字符类的数字 isgraph 判断一个字符是否是可打印字符(ascii码33-126之间的字符) islower 判断一个字符是否是小写字母 isprint 判断一个字符是否是包含空格在内的可打印字符(ascii码32-126之间的字符) ispunct 判断一个字符是否是除空格,字母,数字外的标点符号 isspace 判断一个字符是空白字符(空格,换行符(\n),走纸符(\f),回车符(\r),垂直制表符(\v),水平制表符(\t))

C程序中头文件相互包含精华

.h中一般放的是同名.c文件中定义的变量、数组、函数的声明,需要让.c外部使用的声明。 1)h文件作用 1 方便开发:包含一些文件需要的共同的常量,结构,类型定义,函数,变量申明; 2 提供接口:对一个软件包来说可以提供一个给外界的接口(例如: stdio.h)。 2)h文件里应该有什么 常量,结构,类型定义,函数,变量申明。 3)h文件不应该有什么 变量定义, 函数定义。 4)extern问题 对于变量需要extern; 对于函数不需要因为函数的缺省状态是extern的.如果一个函数要改变为只在文件内可见,加static。 5)include包含问题 虽然申明和类型定义可以重复,不过推荐使用条件编译。 #ifndef _FILENAME_H, #define _FILENAME_H

…… #endif 6)应该在那儿包含h文件 在需要的地方.比如某个提供接口的h文件仅仅被1.c文件需要,那么就在1.c文件里包含。 编写的程序一般会有.H文件和相对应的.C文件,.H文件是声明所用,.C文件是其函数实现部分。在调用时只要包含.H文件即可,我们没有听说过#include "delay.c"这类的程序,同时也不提倡使用这个形式。 在delay.h文件中://对调用的函数声明 #ifndef __DELAY_H__ #define __DELAY_H__ extern void Delayms(unsigned int n);

#endif 在delay.c文件中://函数实现部分#include //for crystal 11.0592M void Delayms(unsigned int n) { unsigned int i,j; for(j=n;j>0;j--) for(i=112;i>0;i--); }

Keil_C51中C语言编程的头文件包含方法

Keil C51中C语言编程的头文件包含方法 一、首先摘抄一写keil官方网站的说明,了解其系统自带的头文件在哪里及如何预处理。 1、 译文:主页/μVision4用户手册 文件夹结构 主页?关于μVision?文件夹结构 安装程序复制开发工具到基础文件夹的子文件夹。默认的基础文件夹包含:C:\Keil。下面的表格列出了所有uVision开发工具的文件夹结构。安装结果可能根据您安装的产品和组件有所变化。 译文:C51开发工具(为经典8051和其扩展种类)

文件夹内容 C:\KEIL\C51\ASM Assembler Source Template and Include files for the Macro Assembler. C:\KEIL\C51\BIN Executable files of theμVision/C51toolchain. C:\KEIL\C51\Examples Example programs. C:\KEIL\C51\FlashMon Configuration files for Flash Monitor and pre-configured versions. C:\KEIL\C51\HLP Online documentation forμVision/C51. C:\KEIL\C51\INC为C编译器的包含文件 C:\KEIL\C51\ISD51Files for ISD51In-System Debugger and pre-configured versions. C:\KEIL\C51\LIB Run-time libraries and CPU startup files. C:\KEIL\C51\Mon51Configuration files for Monitor-51(for Classic8051Devices). C:\KEIL\C51\Mon390Configuration files for Monitor-390(for Dallas Contiguous Mode). C:\KEIL\C51\RtxTiny2RTX51Tiny Version2Real-Time Operation System. 2、 译文:头文件 主页?预处理器?头文件 头文件或包含文件被预处理器包含和处理。它们为你提供了一个方便的方式去声明全局变量、函数原型、声明限制、和宏定义,这些通常在大型的开发工作中贯通始终使用。 #include指令指定要半含的头文件的名字。

stdlib头文件中包含的函数

stdlib.h主要包含的函数 包含函数: 1函数名称: calloc 函数原型: void * calloc(unsigned n,unsign size); 函数功能: 分配n个数据项的内存连续空间,每个数据项的大小为size 函数返回: 分配内存单元的起始地址,如果不成功,返回0 2函数名称: free 函数原型: void free(void* p); 函数功能: 释放p所指的内存区 函数返回: 参数说明: p-被释放的指针 3函数名称: malloc 函数原型: void * malloc(unsigned size); 函数功能: 分配size字节的存储区 函数返回: 所分配的内存区地址,如果内存不够,返回0 4函数名称: realloc 函数原型: void * realloc(void * p,unsigned size); 函数功能: 将p所指出的已分配内存区的大小改为size,size可以比原来分配的空间大或小 函数返回: 返回指向该内存区的指针.NULL-分配失败 5函数名称: rand 函数原型: int rand(void); 函数功能: 产生0到32767间的随机整数(0到0x7fff之间) 函数返回: 随机整数 6函数名称: abort 函数原型: void abort(void) 函数功能: 异常终止一个进程. 7函数名称: exit 函数原型: void exit(int state) 函数功能: 程序中止执行,返回调用过程 函数返回:

参数说明: state:0-正常中止,非0-非正常中止 8函数名称: getenv 函数原型: char* getenv(const char *name) 函数功能: 返回一个指向环境变量的指针 函数返回: 环境变量的定义 参数说明: name-环境字符串 9函数名称: putenv 函数原型: int putenv(const char *name) 函数功能: 将字符串name增加到DOS环境变量中函数返回: 0:操作成功,-1:操作失败 参数说明: name-环境字符串 10函数名称: labs 函数原型: long labs(long num) 函数功能: 求长整型参数的绝对值 函数返回: 绝对值 11函数名称: atof 函数原型: double atof(char *str) 函数功能: 将字符串转换成一个双精度数值 函数返回: 转换后的数值 参数说明: str-待转换浮点型数的字符串 12函数名称: atoi 函数原型: int atoi(char *str) 函数功能: 将字符串转换成一个整数值 函数返回: 转换后的数值 参数说明: str-待转换为整型数的字符串 13函数名称: atol 函数原型: long atol(char *str) 函数功能: 将字符串转换成一个长整数 函数返回: 转换后的数值 参数说明: str-待转换为长整型的字符串 14函数名称: ecvt

包含头文件时尖括号和双引号的区别

include包含头文件的语句中,双引号和尖括号的区别是什么? #incluce ""格式:引用非标准库的头文件,编译器从用户的工作目录开始搜索。双引号表示先在程序源文件所在目录查找,如果未找到则去系统默认目录查找,通常用于包含程序作者编写的头文件;尖括号表示只在系统默认目录或者括号内的路径查找,通常用于包含系统中自带的头文件。 尖括号:在包含文件目录中去查找(包含目录是由用户在设置环境时设置的),而不在源文件目录去查找; 双引号:首先在当前的源文件目录中查找,若未找到才到包含目录中去查找。 详解: 预处理器发现 #include 指令后,就会寻找后跟的文件名并把这个文件的内容包含到当前文件中。被包含文件中的文本将替换源代码文件中的#include指令,就像你把被包含文件中的全部内容键入到源文件中的这个位置一样。 #include 指令有两种使用形式 #include 文件名放在尖括号中 #include “mystuff.h”文件名放在双引号中 尖括号< 和> 括起来表明这个文件是一个工程或标准头文件。查找过程会检查预定义的目录,我们可以通过设置搜索路径环境变量或命令行选项来修改这些目录。

如果文件名用一对引号括起来则表明该文件是用户提供的头文件,查找该 文件时将从当前文件目录(或文件名指定的其他目录)中寻找文件,然后再在标准位置寻找文件。 为什么要包含文件呢? 因为这些文件包含了编译器所需的信息。例如,stdio.h文件通常包含EOF,NULL, getchar()和putchar()的定义。 包含大型头文件并不一定显著增加程序的大小。很多情况下,头文件中的内容是编译器产生最终代码所需的信息,而不是加到最终代码里的具体语句。 被包含的文件还可以含有#include 指示符,由于嵌套包含文件的原因,一个头文件可能会被多次包含在一个源文件中,条件指示符可防止这种头文件的重复处理。 例如: #ifndef BOOKSTORE_H #define BOOKSTORE_H #endif 条件指示符#ifndef 检查BOOKSTORE_H 在前面是否已经被定义,这里BOOKSTORE_H是一个预编译器常量,习惯上预编译器常量往往被写成大写字母,如BOOKSTORE_H在前面没有被定义,则条件指示符的值为真,于是从#ifndef 到#endif 之间的所有语句都被包含进来进行处理。相反,如果#ifndef 指示符的值为假则它与#endif 指示符之间的行将被忽略,为了保证头文件只被处理一次,把如下#define 指示符#define

C语言头文件下包含函数.

math.h常用函数 int abs (int x; double acos (double x; double asin (double x; double atan (double x; double atan2 (double y, double x; double atof (const char *s; double ceil (double x; double cos (double x; double cosh (double x; double exp (double x; double fabs (double x; double floor (double x; double fmod (double x, double y; double frexp (double x, int *exponent; long labs (long x; double ldexp (double x, int exponent; double log (double x; double log10 (double x; double modf (double x, double *ipart; double pow (double x, double y; double sin (double x; double sinh (double x; double sqrt (double x; double tan (double x; double tanh (double x; stdio.h常用函数包括 int fclose (FILE *stream; int fflush (FILE *stream; int fgetc (FILE *stream; int fgetpos (FILE *stream, fpos_t *pos; char * fgets (char *s, int n, FILE *stream; FILE * fopen (const char *path, const char *mode; int fprintf (FILE *stream, const char *format, ...; int fputc (int c, FILE *stream; int fputs (const char *s, FILE *stream; size_t fread (void *ptr, size_t size, size_t n, FILE *stream; FILE * freopen (const char *path, const char *mode, FILE *stream; int fscanf (FILE *stream, const char *format, ...; int fseek (FILE *stream, long offset, int whence; int fsetpos (FILE *stream, const fpos_t *pos; long ftell (FILE *stream; size_t fwrite (const void *ptr, size_t size, size_t n, FILE *stream; int printf (const char *format, ...; int puts (const char *s; int rename (const char *oldname, const char *newname; void rewind (FILE *stream; int scanf (const char *format, ...; stdlib.h常用函数包括stdlib 头文件里包含了C、C++语言的一些函数该文件包含了的C语言标准库函数的定义stdlib.h里面定义了五种类型、一些宏和通用工具函数。类型例如size_t、wchar_t、div_t、ldiv_t和lldiv_t;宏例如EXIT_FAILURE、EXIT_SUCCESS、RAND_MAX和MB_CUR_MAX等等;常用的函数如malloc(、calloc(、realloc(、free(、system(、atoi(、atol(、rand(、srand(、exit(等等。具体的内容你自己可以打开编译器的include目录里面的stdlib.h头文件看看 int abs (int x; int atexit (atexit_t func; double atof (const char *s; int atoi (const char *s; long atol (const char *s; void * bsearch(const void *key, const void *base, size_t nelem, size_t width, int (*fcmp(; void * calloc (size_t nitems, size_t size; div_t div (int numer, int denom; void exit (int status; void free (void *block; char * getenv (const char *n

头文件intrins.h

1..怎么用C51写一个NOP语句呢? 把头文件intrins.h包含进来,然后在需用NOP处调用_nop_();函数即可。 2.c51中的intrins.h库函数 _crol_ 字符循环左移 _cror_ 字符循环右移 _irol_ 整数循环左移 _iror_ 整数循环右移 _lrol_ 长整数循环左移 _lror_ 长整数循环右移 _nop_ 空操作8051 NOP 指令 _testbit_ 测试并清零位8051 JBC 指令 详解: 函数名:_crol_,_irol_,_lrol_ 原型:unsigned char _crol_(unsigned char val,unsigned char n); unsigned int _irol_(unsigned int val,unsigned char n); unsigned int _lrol_(unsigned int val,unsigned char n); 功能:_crol_,_irol_,_lrol_以位形式将val 左移n 位,该函数与8051“RLA”指令相关,上面几个函数不同于参数类型。 例: #include main() { unsigned int y; C-5 1 程序设计37 y=0x00ff; y=_irol_(y,4); /*y=0x0ff0*/ } 函数名:_cror_,_iror_,_lror_ 原型:unsigned char _cror_(unsigned char val,unsigned char n); unsigned int _iror_(unsigned int val,unsigned char n); unsigned int _lror_(unsigned int val,unsigned char n); 功能:_cror_,_iror_,_lror_以位形式将val 右移n 位,该函数与8051“RRA”指令相关,上面几个函数不同于参数类型。 例: #include main() {

C 中#INCLUDE包含头文件带 .H 和不带 .H 的区别

C++中#include包含头文件带.h和不带.h的区别? 如#include和#include包含的东西有哪些不同? 之前在写C++程序的时候只知道使用#include的时候,使用函数前要用using namespace std;导入命名空间,而#include则不用,这个得看C++标准化过程为C++开发者做了哪些有意义的工作。 C++标准化过程中,其中一个环节,解决了以下问题: (1)C++增加了名称空间概念,借以将原来声明在全局空间下的标识符声明在了namespace std下。 (2)统一C++各种后缀名,如.h、.hpp、.hxx等。标准化之前的头文件就是带后缀名的文件,标准化后的头文件就是不带后缀名的文件。C++98规定用户应使用新版头文件,对旧版本头文件不在进行强制规范,但大多数编译器厂商依然提供旧版本头文件,以求向下兼容。 也就是说带.h的头文件是旧标准的,如果想用新的标准的头文件就不要带.h。 另外,为了和C语言兼容,C++标准化过程中,原有C语言头文件标准化后,头文件名前带个c字母,如cstdio、cstring、ctime、ctype等等。这些头文件都可以在C:\Program Files\Microsoft Visual Studio10.0\VC\include这个目录下找到(以VC2010为例)。也就是说,我们如果要用C++标准化了的C语言头文件,就得作如下的转换 #include-->#include #include-->#include #include-->#include 还要提及的一点是,我在看C++标准库的时候,看到一个特殊情况,这两个头文件是完全不同的,因为我发现头文件件包含了;而包含

C语言文件包含与头文件写法

C语言文件包含与头文件写法 C语言文件包含的处理方法: (1)处理时间:(#include)预处理阶段 (2)处理方法:在预处理阶段,系统自动对#include命令进行处理。具体做法是:将包含文件的内容复制到包含语句(#include)处,得到新的文件,然后对新的文件进行编译。 一般情况下包含文件分为两种:包含.h 文件和包含.c文件 包含.c文件的编译和编译多文件程序(包含.h的文件就是如此) 是不同的。 (1)包含.c文件 [cpp] view plaincopy /*file1:main.c */ #include //#include "fun.c" int main() { int a = 5, b = 19; c = a; sun(a, b); printf("\r\n c = %d\r\n", c); return 0; } /*end of file1*/ [cpp] view plaincopy [cpp] view plaincopy /*file2: fun.c*/ int c = 0; void sun(int a, int b) { printf("\r\n a + b = %d\r\n", a+b); [cpp] view plaincopy c = 0; printf("\r\nc = %d\r\n", c); } /*end of file2*/ 编译时,直接去编译main.c文件,预处理器会先把fun.c文件的内容复制到main.c中,然后在对新的main.c进行编译 只需在执行编译命令gccmain.c -o main

相关主题
文本预览
相关文档 最新文档