您的位置:首页 > 其它

第16章 C预处理器和C库 16.5 文件包含: #include

2017-07-22 00:00 218 查看
预处理器发现#includ指令后,就会寻找后跟的文件名并把这个文件的内容包含到当前文件中

被包含文件中的文本将替换源代码文件中的#include指令,就像您把被包含文件中的全部内容键入到源文件中的这个特定位置一样。

#include 指令的两种使用形式

#include <stdio.h>文件名放在尖括号中
#include "mystuff.H"文件名放在双引号中
在UNIX系统中,尖括号告诉预处理器在一个或多个标准系统目录中寻找文件。双引号告诉预处理器先在当前目录(或文件名指定的其他目录)中寻找文件,然后在标准位置寻找文件。

使用#include指令的一些例子

#include <stdio.h>搜索系统目录
#include "hot.h"搜索当前目录
#include "/usr/biff/p.h"搜索/usr/biff目录
对于系统头文件,集成开发环境(IDE)具有标准搜索路径。许多集成开发环境提供菜单选项用于指定使用尖括号时搜索的其他路径。对于UNIX,使用双引号意味着首先搜索本地目录,但是具体搜索哪个目录依赖于编译器。有些编译器搜索源代码所在目录,有些搜索当前工作目录,还有些搜索工程文件所在目录

一般而言,命名文件的方法依赖于系统,但是尖括号与双引号的使用则与系统无关。

习惯上使用后缀.h表示头文件(header file),这类文件包含置于程序头部的信息。头文件经常包含预处理器语句。有些头文件(如stdio.h)由系统提供。您也可以自由创建您自己的头文件。

包含大型头文件并不一定显著增加程序的大小。很多情况下,头文件中的内容是编译器产生最终代码所需的信息,而不是加到最终代码里的具体语句。

16.5.1 头文件:一个实例

假设您要开发一个存放人名的结构,并编写一些使用该结构的函数。您可以在一个头文件中集中进行各种声明。程序清单16.6给出了这个例子:

//names_st.h -- names_st 结构的头文件
//常量
#define SLEN 32

//结构声明
struct names_st
{
char first[SLEN];
char last[SLEN];
}

//类型定义
typedef struct names_st names;

//函数原型定义
void get_names(names *);
void show_names(const names *);

这个文件中含有在头文件中常见的许多内容:#define指令、结构声明、typedef语句和函数原型。

注意这些内容都不是可执行代码,而是编译器用于产生可执行代码的信息。

可执行代码通常在源代码文件中,而不在头文件中。例如,程序清单16.7显示了头文件中函数原型的函数定义。源文件包含了头文件,因此编译器将知道关于names类型的信息。

程序清单16.7 names_st.c源文件

//names_st.c --定义names_st函数
#include <stdio.h>
#include "names_st.h"  //包含头文件

//函数定义
void get_names(names *pn)
{
int i;

printf("Please enter your first name: ");
fgets(pn->first,SLEN,stdin);
i=0;
while(pn->first[i] != '\n' && pn->first[i] != '/0')
i++;
if(pn->first[i]=='\n')
pn->first[i]='\0';
else
while(getchar()!='\n')
continue;

printf("Please enter your last name: ");
fgets(pn->last,SLEN,stdin);
i=0;
while(pn->last[i] != '\n' && pn->last[i] != '\0')
i++;
if(pn->last[i] == '\n')
pn->last[i]='\0';
else
while(getchar()!='\n')
continue;
}

void show_names(const names * pn)
{
printf("%s %s\n",pn->first,pn->last);
}

get_names()函数使用fgets()以避免目标数组溢出。如果被保存的字符串中存在换行符,则用空字符代替换行符。如果没有换行符,则表明fgets()在到达行尾之前就被停止,代码会去掉该行中剩余的输入。

程序清单16.8是使用前面的头文件和源代码文件的示例程序。

程序清单16.8 useheader.c程序

//useheader.c --使用names_st结构
#include <stdio.h>
#include "names_st.h"
//记住链接names_st.c文件

int main(void)
{
name candidate;
get_names(&candidate);
printf("Let's welcome ");
show_names(&candidate);
printf(" to this program!\n");

return 0;
}

下面是一个运行示例:

Please enter your first name: Ian
Please enter your last name: Smersh
Let's welcome Ian Smersh to this program!

关于该程序,应该注意以下几点:

**两个源代码文件都使用了names_st结构,因此,它们都必须包含头文件names_st.h。

**需要编译、链接names_st.c和useheader.c两个源代码文件。

**声明以及类似语句放在头文件names_st.h中,函数定义放在源代码文件names_st.c中。

16.5.2 使用头文件

头文件内容的最常见形式包括:

**明显常量--例如,典型的stdio.h文件定义EOF、NULL和BUFSIZE(标准I/O缓冲区的大小)。

**宏函数--例如,getchar()通常被定义为getc(stdin),getc( )通常被定义为较复杂的宏,而头文件ctype.h通常包含ctype函数的宏定义。

**函数声明--例如,头文件string.h包含字符串函数系列的函数声明。在ANSI C中,声明采用函数原型形式。

**结构模板定义--标准I/O函数使用FILE结构,该结构包含文件及文件相关缓冲区的信息。头文件stdio.h中存放FILE结构的声明。

**类型定义--可以使用指向FILE的指针作为参数调用I/O函数。通常,stdio.h用#define或typedef使得FILE代表指向FILE结构的指针。与之类似,size_t和time_t类型也在头文件中定义。

另外,可以使用头文件来声明多个文件共享的外部变量。此时,可以在包含函数声明的源代码文件中定义一个具有文件作用域、外部链接的变量。

int status=0; //文件作用域,源代码文件中

接着,可以在与源代码文件相关联的头文件中进行引用声明

extern int status; //头文件中

该行代码会出现在包含了头文件的任何文件中并使得使用这个函数系列的文件可以使用该变量。在源代码文件中包含该头文件后该声明也会出现但是只要声明类型一致,那么在同一文件中使用定义声明和引用声明就不会出现问题。

需要包含头文件的另一种情况是:使用具有文件作用域、内部链接和const限定词的变量或数组。使用const可以避免值被意外改变。使用static后,每个包含该头文件的文件都获得一份该常量的副本。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐