4.1 什么是连接器
一个C程序可能是由多个分别编译的部分组成,这些不同部分通过一个连接器的程序,合并为成一个整体;
某些C语言实现,提供了一个成为 lint 的程序,可以捕获到连接器不能识别的错误,切记一定要使用;
4.2 声明与定义
int a;
如果 “int a;” 的位置出现在所有的函数体之外,那么它就被称为 外部对象a的定义;
注: extern 是声明语句
static int b=9; // 变量b的定义
int func1()
{
int a = 0; // 变量a的声明
a=b;
}
4.3 命令冲突与static修饰符
两个具有相同名称的外部对象实际上代表的是同一个对象,即使编程者的本意并非如此,但系统却会如此处理(无论两个源文件中的外部变量a是否应该共享);不过有的连接器,会禁止外部变量的重复定义;
内部使用的变量和函数,增加static 修饰符
static 修饰符会限定 变量 的作用域限定在一个源文件宏,不会被其它源文件引用;
如果一个 函数 仅仅被同一个源文件中的其它函数调用,那么我们就应该声明该函数为 static;
// 对同一个源文件中,增加static不会对功能有影响
static int a=0;
int a=0;
static int func1()
{
int b=0; // 局部变量不会有命名冲突
}
int func1()
{
int b=0;
}
4.4 形参,实参和返回值
形参:函数定义时候的参数;
实参:函数使用时候的参数;
int func1(int a) // a 是形参
{
// something
}
int b = 9;
func(b); // b 是实参
如果一个函数在被定义或声明之前被调用,那么它的返回类型就 默认为整形;
main()
{
printf("%g \n",square(0.3)); // 先使用后定义,会报类型不匹配错误
}
double square(double)
{
double result = 0;
// something
return result;
}
4.5 检查外部类型
.h文件声明到外部的函数变量,应尽可能匹配实际含义,不可简写;
简写可能会造成 名称一致,类型不一致的重名问题;
/***.h文件****/
extern int a;
/***.c文件****/
char a;
数组河指针的外部声明
/***.c文件****/
char file_name[] = "passwd";
/***.h文件****/
extern char *file_name; // 错误,一个是数组类型,一个是指针类型
extern char file_name[]; // 正确写法
// 或者
char *file_name = "passwd"; // .c文件
extern char *file_name; // .h文件
如果一个未声明的标识符后跟一个开括号,那么它将被视为一个返回整形的函数
main()
{
double s;
s=sqrt(2); // 被认为 extern int sqrt(); 和实际的 double 不相符
printf("%g \n", s);
}
4.6 头文件
只要源文件file.c中 file_name 的各个声明是一致的,而且这些声明中只有一个是 file_name 的定义,这样写就是合法的;
// file.h
extern char file_name[];
// file.c
include "file.h"
char file_name[]="passwd";
// file.c 等价于
extern char file_name[];
char file_name[]="passwd";