12-头文件示例
16.5.1 头文件示例
假设你开发了一个存放人名的结构,还编写了一些使用该结构的函数。可以把不同的声明放在头文件中。程序清单16.6演示了一个这样的例子。
程序清单16.6 names_st.h 头文件
// names_st.h -- names_st 结构的头文件
// 常量
#include <string.h>
#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 *);
char * s_gets(char * st, int n);
该头文件包含了一些头文件中常见的内容: #define 指令、结构声明、 typedef 和函数原型。注意,这些内容是编译器在创建可执行代码时所需的信息,而不是可执行代码。为简单起见,这个特殊的头文件过于简单。通常,应该用 #ifndef 和 #define 防止多重包含头文件。我们稍后介绍这些内容。
可执行代码通常在源代码文件中,而不是在头文件中。例如,程序清单16.7中有头文件中函数原型的定义。该程序包含了 names_st.h 头文件,所以编译器知道 names 类型。
程序清单16.7 name_st.c 源文件
// names_st.c -- 定义 names_st.h中的函数
#include <stdio.h>
#include "names_st.h" // 包含头文件
// 函数定义
void get_names(names * pn)
{
printf("Please enter your first name: ");
s_gets(pn->first, SLEN);
printf("Please enter your last name: ");
s_gets(pn->last, SLEN);
}
void show_names(const names * pn)
{
printf("%s %s", pn->first, pn->last);
}
char * s_gets(char * st, int n)
{
char * ret_val;
char * find;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
find = strchr(st, '\n'); // 查找换行符
if (find) // 如果地址不是NULL,
*find = '\0'; // 在此处放置一个空字符
else
while (getchar() != '\n')
continue; // 处理输入行中的剩余字符
}
return ret_val;
}
get_names() 函数通过 s_gets() 函数调用了 fgets() 函数,避免了目标数组溢出。程序清单16.8使用了程序清单16.6的头文件和程序清单16.7的源文件。
程序清单16.8 useheader.c 程序
// useheader.c -- 使用 names_st 结构
#include <stdio.h>
#include "names_st.h"
// 记住要链接 names_st.c
int main(void)
{
names 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源代码文件。 - 声明和指令放在
nems_st.h头文件中,函数定义放在names_st.c源代码文件中。