C语言多文件模块化编程 C语言多文件共用一种结构体类型

很多初学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;
}

其余四个文件

scrn20141027224313

公用结构体

由于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把这些文件都添加进工程

scrn20141028124218

现在各个文件内容如下

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); 就可以啦

 

如果文章对你有帮助,欢迎点赞或打赏(金额不限)。你的打赏将全部用于支付网站服务器费用和提高网站文章质量,谢谢支持。

版权声明:

本文由 原创,商业转载请联系作者获得授权。
非商业转载请注明作者 雅乐网 ,并附带本文链接:
https://www.yalewoo.com/c_multiple_file_programming.html

上一篇:

下一篇:

我要评论

验证码*: 5 + 4 =