很多初学C语言的同学往往一个程序就是一个文件,好一点的只有一个.h文件。甚至有的初学者会把函数放到一个.c文件,然后在main.c中include那个.c文件 ==(我就干过这种事)。下面雅乐网说一下多文件编程方面自己的经验(菜鸟教程)。
1. include的作用
把C语言源代码变成可执行文件的时候,编译器的第一步会进行预处理,把include的文件的内容全部复制到本文件。
比如我们有一个header.h文件内容如下
#define MAX_NAME_LEN 30
struct student
{
int id;
char name[MAX_NAME_LEN];
};
我们还有一个main.c文件
#include "header.h"
int main(void)
{
return 0;
}
我们可以使用gcc的-E选项来对一个文件进行预处理,
可以看到预处理后的内容是这样的
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "main.c"
# 1 "header.h" 1
struct student
{
int id;
char name[30];
};
# 2 "main.c" 2
int main(void)
{
return 0;
}
可以看出预处理的时候会把include的文件的内容全部复制过来。
2. 一个文件的简单程序
我们有一个学生信息处理程序,只有一个student结构体(在上面header.h里的一样),和三个函数改变id的 change_id(struct student * p, int id)和改变姓名的change_name(struct student* p, char * pchar)。该程序现在是这个样子:
#include <stdio.h>
#define BOOL int
#define TRUE 1
#define FALSE 0
#define MAX_NAME_LEN 30
struct student
{
int id;
char name[MAX_NAME_LEN];
};
BOOL change_id(struct student * p, int id);
BOOL check_id (int id);
void change_name(struct student * p, char * pchar);
int main(void)
{
int op = 1;
int id;
char name[MAX_NAME_LEN];
struct student zhangsan = {1, "lisi"};
while (op != 0)
{
printf("0. exit\n");
printf("1. change_id\n");
printf("2. change_name\n");
scanf("%d", &op);
switch(op)
{
case 1:
{
printf("input id: ");
scanf("%d", &id);
if (change_id(&zhangsan, id) == TRUE)
;
else
printf("id is not corrext\n");
break;
}
case 2:
{
printf("input name\n");
scanf("%s", name);
change_name(&zhangsan, name);
break;
}
default:
{
break;
}
}
printf("now zhangsan\'s id is %d.\n", zhangsan.id);
printf("and zhangsan\'s name is %s.\n", zhangsan.name);
}
return 0;
}
BOOL change_id(struct student * p, int id)
{
if (check_id(id) == FALSE)
{
return FALSE;
}
else
{
p->id = id;
return TRUE;
}
}
BOOL check_id (int id)
{
if (id > 100)
{
return FALSE;
}
else
{
return TRUE;
}
}
void change_name(struct student * p, char * pchar)
{
int i;
for (i = 0; pchar[i] != '\0' && i < MAX_NAME_LEN; ++i)
{
p->name[i] = pchar[i];
}
}
3. 拆分成多文件
上面这个程序只是为了说明怎么变成多文件,不要吐槽程序的功能……
分模块
首先,我们想把change_id做成一个模块,把change_name做成一个模块。
C语言中一般一个模块由一个.c文件和一个同名的.h文件组成。其中,.h文件用来描述该模块的接口,也就是函数,用来存放声明,而不能放定义。.c文件放具体的函数定义。而函数的声明就放在.h文件里。
首先我新建四个文件 change_id.h change_id.c change_name.h change_name.c
然后把相应的函数分别复制过去。其中check_id是在change_id里面用的,我们把它们放到一起。现在程序变成了这样
main.c
#include <stdio.h>
#define BOOL int
#define TRUE 1
#define FALSE 0
#define MAX_NAME_LEN 30
struct student
{
int id;
char name[MAX_NAME_LEN];
};
int main(void)
{
int op = 1;
int id;
char name[MAX_NAME_LEN];
struct student zhangsan = {1, "lisi"};
while (op != 0)
{
printf("0. exit\n");
printf("1. change_id\n");
printf("2. change_name\n");
scanf("%d", &op);
switch(op)
{
case 1:
{
printf("input id: ");
scanf("%d", &id);
if (change_id(&zhangsan, id) == TRUE)
;
else
printf("id is not corrext\n");
break;
}
case 2:
{
printf("input name\n");
scanf("%s", name);
change_name(&zhangsan, name);
break;
}
default:
{
break;
}
}
printf("now zhangsan\'s id is %d.\n", zhangsan.id);
printf("and zhangsan\'s name is %s.\n", zhangsan.name);
}
return 0;
}
其余四个文件
公用结构体
由于changeid和changename模块都用到了struct student类型的结构体,必须在每个.c中声明。下面我们把声明写到一个公用头文件里header.h
#include <stdio.h>
#define BOOL int
#define TRUE 1
#define FALSE 0
#define MAX_NAME_LEN 30
struct student
{
int id;
char name[MAX_NAME_LEN];
};
然后在main.c change_id.c change_name.c开头部分均添加#include “header.h”
在mian.c中添加
#include “change_id.h”
#include “change_name.h”
就可以了。不过现在由于是多文件,编译链接的时候需要指定多个文件。我们也可以使用IDE把这些文件都添加进工程
现在各个文件内容如下
main.c
#include "header.h"
#include "change_id.h"
#include "change_name.h"
int main(void)
{
int op = 1;
int id;
char name[MAX_NAME_LEN];
struct student zhangsan = {1, "lisi"};
while (op != 0)
{
printf("0. exit\n");
printf("1. change_id\n");
printf("2. change_name\n");
scanf("%d", &op);
switch(op)
{
case 1:
{
printf("input id: ");
scanf("%d", &id);
if (change_id(&zhangsan, id) == TRUE)
;
else
printf("id is not corrext\n");
break;
}
case 2:
{
printf("input name\n");
scanf("%s", name);
change_name(&zhangsan, name);
break;
}
default:
{
break;
}
}
printf("now zhangsan\'s id is %d.\n", zhangsan.id);
printf("and zhangsan\'s name is %s.\n", zhangsan.name);
}
return 0;
}
header.h
#include <stdio.h>
#define BOOL int
#define TRUE 1
#define FALSE 0
#define MAX_NAME_LEN 30
struct student
{
int id;
char name[MAX_NAME_LEN];
};
change_id.h
BOOL change_id(struct student * p, int id); BOOL check_id (int id);
change_id.c
#include "header.h"
BOOL check_id (int id)
{
if (id > 100)
{
return FALSE;
}
else
{
return TRUE;
}
}
BOOL change_id(struct student * p, int id)
{
if (check_id(id) == FALSE)
{
return FALSE;
}
else
{
p->id = id;
return TRUE;
}
}
change_name.h
void change_name(struct student * p, char * pchar);
change_name.c
#include "header.h"
void change_name(struct student * p, char * pchar)
{
int i;
for (i = 0; pchar[i] != '\0' && i < MAX_NAME_LEN; ++i)
{
p->name[i] = pchar[i];
}
}
函数作用域
只在本文件中用到的函数可以在.c的函数前面用static修饰,这样函数作用于就是本文件了。如果一个.c的函数需要在其他.c中使用,只需要去掉static 然后再需要使用的地方再用extern 声明。
例如我们想在change_name.c中使用check_id函数,只需要在change_name上面声明 extern BOOL check_id (int id); 就可以啦


支付宝打赏
微信打赏