编写大规模的C语言程序
来源:互联网 发布:联通网络信号怎么样 编辑:程序博客网 时间:2024/05/01 14:35
为了支持大规模C程序的开发,往往需要把程序分割为一定数量的源文件。C语言的源文件包括两类,一类是实现文件(.c
),一类是头文件(.h
)。一般地,实现文件主要包括函数和变量的定义,而头文件的作用是在多个定义文件中共享函数原型、宏定义和类型定义、变量声明等信息。
将一个程序分为多个源文件的方式组织程序具有很多好处,比如:
- 将相关(例如完成同一功能或关于同一事物)的函数和变量放在单独的文件中,便于理解程序结构。
- 可单独对每个源文件进行编译,避免每次修改都要重新编译整个程序,提高编译速度。
- 可以将程序的一部分文件用于其他程序,有利于函数重用。
头文件
使用文件包含指令#include
为定义文件包含需要的头文件。最好不要在使用#include
时包含绝对路径信息,这样可能会造成在不同机器或操作系统的不可移植。头文件自身可以使用#include
文件包含指令包含其他头文件。通常将#error
放在头文件中用来检查不应该使用该头文件的情况。
利用头文件共享宏定义和类型定义
使用#define
的宏定义和typedef
的类型定义都可以放在头文件中。这样使得程序易于修改,且避免了不同文件中同一个宏名或类型定义不同导致的问题。
/************************************** * macro_typedef.h * * * * C语言共享宏定义和类型定义 * **************************************/#define N 100typedef int BOOL;/************************************** * file1.c * * * * 引用共享的宏或类型定义 * **************************************/#include <stdio.h>#include "macro_typedef.h"int main(){ printf("N = %d\n", N); BOOL i = 10; printf("i = %d\n", i); return 0;}/************************************** * file2.c * * * * 引用共享的宏或类型定义 * **************************************/#include <stdio.h>#include "macro_typedef.h"int main(){ printf("N = %d\n", N); BOOL i = 15; printf("i = %d\n", i); return 0;}
同一个类型定义可以出现在一个程序中的多个文件中。
/************************************** * file3.c * * * * 测试同一个类型定义用到一个C程序的多个文件 * **************************************/#include <stdio.h>#include "macro_typedef.h"void print(){ printf("N = %d,", N); BOOL i = 50; printf("i = %d\n", i);}
利用头文件共享函数原型
可以把函数定义的原型放在头文件中,在所有调用该函数的实现文件中包含该头文件。只将打算被其他定义文件使用的函数原型放在头文件中。
/************************************** * function_define.c * * * * C语言中的函数定义 * **************************************/#include <stdio.h>int Sum(int n){ int i = 1; int sum = 0; for (; i <= n; i++) sum += i; return sum;}void Print(int n, int sum){ printf("从1到%d的和为%d\n", n, sum);}/*************************************** * function_define.h * * * * C语言函数原型声明头文件 * ***************************************/int Sum(int);void Print(int, int);/************************************* * file1.c * * * * 使用其他文件定义的函数 * *************************************/#include "function_define.h"int main(){ int n = 10; Print(n, Sum(n)); return 0;}/************************************* * file2.c * * * * 使用其他文件定义的函数 * *************************************/#include "function_define.h"int main(){ int n = 5; Print(n, Sum(n)); return 0;}
利用头文件共享变量声明
把全局变量的定义定义文件中,同时将变量的声明(使用extern
关键字)放在头文件里。通过包含该头文件就可以在其他文件中访问全局变量。确保变量的声明和定义一致。
/************************************** * global_define.c * * * * C语言定义全局变量 * **************************************/float velocity = 100.0f;void Fast(){ velocity *= 1.1;}void Slow(){ velocity *= 0.9;}/************************************** * global_define.h * * * * 定义全局变量声明头文件 * **************************************/extern float velocity;void Fast();void Slow();/*************************************** * file1.c * * * * C语言共享全局变量 * ***************************************/#include <stdio.h>#include "global_define.h"int main(){ Fast(); printf("当前速度: %g\n", velocity); return 0;}/*************************************** * file1.c * * * * C语言共享全局变量 * ***************************************/#include <stdio.h>#include "global_define.h"int main(){ Slow(); printf("当前速度: %g\n", velocity); return 0;}
不要多次包含同一个头文件
如果头文件中只包含宏定义、函数原型或变量声明,则多次包含头文件并不会产生编译错误,但是如果头文件中包含类型定义,那么就会产生编译错误。
为了防止多次包含同一个头文件,可以使用#ifndef
和#endif
指令来将文件内容包裹起来,以保证在一个文件中,这段文件内容只被包含一次。
#ifndef 宏名称#define 宏名称...文件内容#endif
首次包含时,宏应该未定义,所以预处理器保留文件内容,而如果再次包含时,由于宏已被定义,则#ifndef
和#endif
文件内容将被丢弃。
/*************************************** * file1.h * * * * 使用#ifndef和#endif避免多次包含 * ***************************************/#ifndef _FILE1_H_#define _FILE1_H_#define N 20typedef int Integer;#endif/************************************** * file1.c * * * * 使用file1.h头文件 * **************************************/#include <stdio.h>#include "file1.h"int main(){ printf("N = %d,", N); Integer i = 100; printf("i = %d\n", i); return 0;}
C语言程序的划分原则
- 把相关函数集合放在单独的定义文件中(*.c)。
- 创建和定义文件名相同的头文件(*.h),并在定义文件中包含该头文件。
- 将头文件添加到所有需要使用其中声明的函数等信息的文件。
- 添加程序入口函数main函数,并将其写在一个与应用程序名字相同的定义文件内。
大规模C程序的构建
大多数编译器允许单独一步构建C程序,例如gcc的一般格式为:
gcc -o 可执行文件名 文件1.c 文件2.c ... 文件n.c
编译器首先将这些定义文件编译成目标代码,然后再由链接器将这些代码链接成目标文件,目标文件的名称由-o
选项指定。
makefile
当源文件过多时,上面的编译命令将变得非常复杂,而且当一个源文件发生改变时,所有文件都要重新编译。针对这些问题,为了更容易构建大规模的程序,可以利用makefile
文件。makefile
文件包含了程序部分的文件和文件之间的依赖性。makefile
的基本格式如下:
目标 : 依赖文件列表 目标由依赖文件生成命令
在创建了makefile
之后,就可以直接使用make
工具构建程序。
/************************************** * add.h * * * * 加法器,执行加法运算 * **************************************/float add(float, float);/************************************* * add.c * * * * 加法器的实现 * *************************************/#include "add.h"float add(float a, float b){ return a + b;}/************************************** * minus.h * * * * 减法器 * **************************************/float minus(float, float);/************************************** * minus.c * * * * 减法器的实现 * **************************************/#include "minus.h"float minus(float a, float b){ return a - b;}/************************************** * calculate.c * * * * 主函数,利用加减法器计算 * **************************************/#include <stdio.h>#include "add.h"#include "minus.h"int main(){ float a, b; printf("输入两个浮点数:"); scanf("%f%f",&a,&b); printf("%g和%g的和为%g\n", a, b, add(a, b)); printf("%g和%g的差为%g\n", a, b, minus(a, b)); return 0;}
Makefile文件:
calc : calculate.o add.o minus.o gcc -o calc calculate.o add.o minus.ocalculate.o : calculate.c minus.h add.h gcc -c calculate.cminus.o : minus.c minus.h gcc -c minus.cadd.o : add.c add.h gcc -c add.c.PHONEY : cleanclean : rm *.o calc
多文件链接时可能出现的错误
链接期间经常出现的是无法解决外部引用的错误,可能原因有以下几种:
- 变量或函数名拼写错误。
- 连接器找不到指定的文件。
- 链接器找不到程序中使用的库函数。
重新构建的几种情况
- 只有一个定义文件修改。只编译该源文件并重新链接程序。
- 改变头文件。重新编译包含此头文件的所有文件,重新链接程序。
makefile
可根据文件的时间自动重新构建,并且按照以上方式,只编译被修改的源文件。
程序外定义宏
C语言的程序需要依赖一些宏的定义,大多数编译器(包括gcc)支持通过选项-D
定义宏的值,如果没有指定值则默认为1.同时一些编译器也提供了-U
选项,用于取消从外部取消程序中宏的定义。
/*************************************** * external_macro.c * * * * C语言使用外部宏 * ***************************************/#include <stdio.h>int main(){#ifdef DEBUG printf("现在处于Debug模式\n");#endif#if OPTION == 1 printf("当前选项为1\n");#elif OPTION == 2 printf("当前选项为2\n");#else #error wrong options#endif}
参考文献
- K.N. King 著,吕秀峰 译. C语言程序设计-现代方法. 人民邮电出版社
- 编写大规模的C语言程序
- C语言程序编写
- C语言程序编写
- C语言编写的接口程序
- C语言编写的接口程序
- C语言编写的bmp读写程序
- c语言编写的一些小程序
- c语言编写程序的优点
- C语言编写的加法程序
- C语言编写的简单计算器程序
- C语言:折半查找的程序编写
- C语言编写时钟程序
- C语言编写五子棋程序
- C语言编写CGI程序
- C语言编写GUI程序
- C语言编写程序计时
- C语言编写的贪食蛇程序.c
- C语言编写的贪食蛇程序.c
- BZOJ 1696 [Usaco2007 Feb]Building A New Barn新牛舍 数学
- git解决误操作
- Android API Guides –System Permissions
- 8.18学习总结
- maven 自定议archetype设置
- 编写大规模的C语言程序
- VS2012自带的 性能分析 工具使用实例
- android ListView之——BaseAdapter使用
- 采集ajax加载生成的网页
- .Net 雜談
- Leetcode#74||Search a 2D Matrix
- 深度学习(deep learning)如果有春天,先得摆脱高能耗高资源依赖的局面
- Linux————TCP/IP协议
- 基于深度优先算法的有向图环路检测