1 迷宫问题的工程实例
该工程包含三个头文件main.h、stack.h、maze.h,和三个源文件main.c、stack.c、maze.c。
/*头文件main.h*/
#ifndef MAIN_H
#define MAIN_H
typedef struct point {int row, col;}item_t;
#define MAX_ROW 5
#define MAX_COL 5
#endif
/*源文件main.c*/
#include <stdio.h>
#include "main.h"
#include "stack.h"
#include "maze.h"
struct point predecessor[MAX_ROW][MAX_COL] = {
{{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1}},
{{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1}},
{{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1}},
{{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1}},
{{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1}},
};
void visit(int row, int col, struct point pre)
{
struct point visit_point = {row, col};
maze[row][col] = 2;
predecessor[row][col] = pre;
push(visit_point);
}
int main(void)
{
struct point p = {0, 0};
maze[p.row][p.col] = 2;
push(p);
while (!is_empty())
{
p = pop();
if (p.row == MAX_ROW - 1 && p.col == MAX_COL - 1)
break;
if (p.col + 1 < MAX_COL && maze[p.row][p.col + 1] == 0)
{
visit(p.row, p.col + 1, p);
}
if (p.row + 1 < MAX_ROW && maze[p.row+1][p.col] == 0)
{
visit(p.row +1, p.col, p);
}
if (p.col -1 >= 0 && maze[p.row][p.col - 1] == 0)
{
visit(p.row, p.col - 1, p);
}
if (p.row -1 >= 0 && maze[p.row - 1][p.col] == 0)
{
visit(p.row - 1, p.col, p);
}
print_maze();
}
if (p.row == MAX_ROW - 1 && p.col == MAX_COL - 1)
{
printf("(%d, %d)\n", p.row, p.col);
while (predecessor[p.row][p.col].row != -1)
{
p = predecessor[p.row][p.col];
printf("(%d, %d)\n", p.row, p.col);
}
}
else
{
printf("No path!\n");
}
return 0;
}
/*头文件stack.h*/
#ifndef STACK_H
#define STACK_H
#include "main.h"
extern void push(item_t);
extern item_t pop(void);
extern int is_empty(void);
#endif
/*源文件stack.c*/
#include "stack.h"
static item_t stack[512];
static int top = 0;
void push(item_t p)
{
stack[top++] = p;
}
item_t pop(void)
{
return stack[--top];
}
int is_empty(void)
{
return top == 0;
}
/*头文件maze.h*/
#ifndef MAZE_H
#define MAZE_H
#include "main.h"
extern int maze[MAX_ROW][MAX_COL];
void print_maze(void);
#endif
/*源文件maze.c*/
#include <stdio.h>
#include "maze.h"
int maze[MAX_ROW][MAX_COL] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
void print_maze(void)
{
int i, j;
for (i = 0; i < MAX_ROW; i++)
{
for (j = 0; j < MAX_COL; j++)
printf("%d ", maze[i][j]);
putchar('\n');
}
printf("*******************\n");
}
但这不是好方法,因为如果其中的maze.c文件做了修改,则需要把所有源文件编译一遍,即使其他的源文件和头文件都没有修改也需要跟着重新编译。
2 Makefile文件
#Makefile文件
main : main.o stack.o maze.o
gcc main.o stack.o maze.o -o main
main.o : main.c main.h stack.h maze.h
gcc -c main.c
stack.o : stack.c stack.h main.h
gcc -c stack.c
maze.o : maze.c maze.h main.h
gcc -c maze.c
clean:
@echo "cleanning project"
-rm main *.o
@echo "clean completed"
.PHONY : clean
[root]# make
make: Warning: File `makefile' has modification time 4.5e+03 s in the future
gcc -c main.c
gcc -c stack.c
gcc -c maze.c
gcc main.o stack.o maze.o -o main
make: 警告:检测到时钟错误。您的创建可能是不完整的。
[root]# make clean
make: Warning: File `makefile' has modification time 3.5e+03 s in the future
cleanning project
rm main *.o
clean completed
make: 警告:检测到时钟错误。您的创建可能是不完整的。
[root]#
2.1 make处理Makefile文件的过程分为两个阶段:
1)从前到后读取所有规则,建立起完整的依赖关系图。
2)从缺省目标或者命令执行指定的目标开始,根据依赖关系图选择适当的规则执行。
2.2Makefile文件中一些约定的目标名字:
all:执行主要的编译工作,通常用作缺省目标。
install:执行编译后的安装工作,把可执行文件、配置文件、文档等分别拷贝到不同的安装目录。
cean:删除编译生成的二进制文件
distclean:不仅删除编译生成的二进制文件,也删除其他的生成文件。
2.3 Makefile中的变量
Makefile中的变量包括自己定义的变量和一些特殊变量。
1)自定义变量
Makefile中的变量就像C语言中的宏定义一样,代表一串字符(或者空字符串)。变量名加上括号和$符号,则表示将变量的值展开。
自定义变量的格式1:
#格式1: 变量名 = 值
all:
@echo $(foo)
foo = Ah $(bar)
bar = Huh?
通过=号定义一个变量,如果=号右边有需要展开的形式,如$(bar),并不会在定义这个变量时立即展开,而是直到这个变量取值时才进一步展开,也叫做递归展开。
自定义变量的格式2:
#格式2: 变量名 := 值
all:
@echo $(foo)
bar := Huh?
foo := Ah $(bar)
通过:=号定义的变量在定义时就立即展开=右边,而不是等到变量取值时再展开。
2)特殊变量
$@,表示规则中的目标
$*,表示模式中规则中的stem
$<,表示规则中的第一个条件
$?,表示规则中所有比目标新的条件,组成一个列表,以空格分隔
$^,表示规则中的所有条件,组成一个列表,以空分隔,如果这个列表中有重复的项,则消除重复的项。