举例:不规范的头文件 // in header. h #ifndef header H #define Header H extern void foo1();/*函数声明 extern int a1 /*外部变量声明* struct a: /*前置声明结构A int az, /全局变量定义,应当避免 void Foo2o //函数定义,应当避免 typedef struct /*结构B定义* int 如果有多个程序模块文件,例如Ac和 Bc,他们都 sinclude了该头文件。那么当 struct A m 他们被分别编译的,都生成了一份全局 }B; 变量a2和函数F0O2。编译是ok的,但是 #endi千 在Link阶段,会出现重复定义的冲突 导致失败
// in header.h #ifndef _HEADER_H #define _HEADER_H extern void Foo1(); /*函数声明 */ extern int a1; /*外部变量声明 */ struct A; /*前置声明结构A */ int a2; //全局变量定义,应当避免 void Foo2() //函数定义,应当避免 {} typedef struct /* 结构B定义 */ { int i; struct A m; }B; #endif 16 如果有多个程序模块文件,例如A.c和 B.c,他们都include了该头文件。那么当 他们被分别编译的,都生成了一份全局 变量a2和函数Foo2。编译是ok的,但是 在Link阶段,会出现重复定义的冲突, 导致失败
头文件的作用 ◇通过头文件了解函数功能 ◇用户经常不能拿到源代码(涉密),但是可以 拿到头文件和庳文件(编译后的二进制文件)。 ◇用户可以按照头文件中的(接口)函数声明, 调用库函数,而不必关心接口怎么实现的。 ◇编译器会从库中提取相应的二进制代码。 ◇例如我们使用 pr intf, scanf.标准库函数 ◇通过头文件能加强类型安全检查 ◇如果某个接口/函数被实现或被使用时,其方式 与头文件中的声明不一致,编译器就会报错 该简单规则能大大减轻程序员调试和改错负担1
通过头文件了解函数功能 用户经常不能拿到源代码(涉密),但是可以 拿到头文件和库文件(编译后的二进制文件)。 用户可以按照头文件中的(接口)函数声明, 调用库函数,而不必关心接口怎么实现的。 编译器会从库中提取相应的二进制代码。 例如我们使用printf,scanf标准库函数 通过头文件能加强类型安全检查 如果某个接口/函数被实现或被使用时,其方式 与头文件中的声明不一致,编译器就会报错 该简单规则能大大减轻程序员调试和改错负担 17
宏定义共 define命令 ◇# define宏名标识符宏定义字符串 #def ine p 3. 14 编译时,把程序中所有与宏名相同的标识符,用宏 定义字符串替代 说明: 宏名一般用大写字母,以与变量名区别 宏定义不是C语句,后面不得跟分号 宏定义可以嵌套使用 ◇多用于符号常量、简单的操作和函数等 #define MAX(a, b)(a>b)?(a:b)
#define 宏名标识符 宏定义字符串 #define PI 3.14 编译时,把程序中所有与宏名相同的标识符,用宏 定义字符串替代 说明: 宏名一般用大写字母,以与变量名区别 宏定义不是C语句,后面不得跟分号 宏定义可以嵌套使用 多用于符号常量、简单的操作和函数等 #define MAX(a, b) ((a)>(b) ? (a) : (b))
宏基本定义 ◇宏定义可以写在程序中任何位置,它的作 用范围从定义书写处到文件尾。 ◇可以通过“# undef”强制指定宏的结束范 围
宏定义可以写在程序中任何位置,它的作 用范围从定义书写处到文件尾。 可以通过“#undef”强制指定宏的结束范 围