链接多个文件
在一个文件中可能需要引用另外一个文件中定义的全局变量或函数。
下面的例子是一个简单的数组操作程序,在operate.c文件中,定义了一个全局变量的数组和 一些数组操作。
#include <stdio.h>
#define MAX 5
int array[MAX] = {2, 7, 6, 4, 8};
//求和
int sum()
{
int i;
int n;
n = 0;
for(i = 0; i < MAX; i++) {
n += array[i];
}
return n;
}
//得到数组中最大的元素
int get_max()
{
int max;
int i;
i= 0;
max = array[i];
for(i = 0; i < MAX; i++) {
if(array[i] > MAX){
max = array[i];
}
}
return max;
}
//输出数组中每个元素的值
void print()
{
int i;
for(i = 0; i < MAX; i++){
printf("array[%d] : %d\n", i+1, array[i]);
}
}
在main函数中使用:
#include <stdio.h>
extern int array[]; //导出全局变量的声明
extern int sum(); //导出函数的声明
extern int get_max();
extern void print();
int main(void)
{
int all, max;
all = sum();
max = get_max();
print();
printf("the sum is %d, the max is %d\n", all, max);
return 0;
}
运行结果如下:
array[1] : 2
array[2] : 7
array[3] : 6
array[4] : 4
array[5] : 8
the sum is 27, the max is 8
链接时符号解析规则 首先看两个概念:
- 声明:表示告知编译器该变量的存在 如:int a;
- 定义:不仅告知变量的存在,而且为该变量赋值,并分配内存空间 如:int a = 1;
当该变量的作用域内只有声明,而没有该变量的定义时,编译器会自动将第一个声明认为是 变量的定义,如下:
{
//在这里声明变量b,由于在 该函数内找不到对变量b的定义
//因此该声明被认为是变量的定义,这时分配了4个姊jie妹存储空间给b
int b;
b = 2; //这是对变量b的赋值,不是定义
return a + b;
}
C语言中的符号解析规则如下;
- 不允许有多个符号的定义,这里的符号指的是变量或者函数。
- 如果有一个符号定义和多个符号的声明,则选择被定义的符号。
- 如果有多个符号的声明,则从其中任选一个作为符号的定义。
链接规则的应用
实例1:
a.c中包含一个全局变量a的定义
#include <stdio.h>
int a = 123; //一个全局变量
int main(void)
{
return 0;
}
b.c中也包含一个全局变量的定义
int a = 321; //同名的全局变量
void f(void)
{
printf("function %f\n");
}
该例会造成链接错误,原因是两个文件中都对一个变量进行了定义,违反了第一条规则。
实例2
a.c中包含一个全局变量a的定义
#include <stdio.h>
void f(void); //函数的声明
int a = 123; //全局变量的定义
int main(void)
{
f(); //调用函数
printf("a = %d\n", a); //输出全局变量
return 0;
}
b.c中包含一个全局变量a的声明:
int a; //全局变量的声明
void f()
{
a = 121; //对全局变量赋值
}
由于两个源文件中出现了对变量a的定义和声明,因此其符号解析符合第二条规则,所以全 局变量a在f()中被修改为121. 输出为:a = 121
实例3
a.c中包含全局变量a定义
#include <stdio.h>
void f(void); //函数的声明
int a = 123; //全局变量的定义
int b = 321;
int main(void)
{
f(); //调用函数
printf("a = %d, b = %d\n", a, b); //输出变量a和b
return 0;
}
b.c中包含对全局变量a的声明
double a; //全局变量的声明
void f()
{
a = 0.0; //对变量a赋值
}
运行结果为: a = 0, b = 0
这是为什么(⊙o⊙)? 两个源文件分别包含全局变量a的定义和全局变量a的声明,根据第二条规则,不会出现链接错误,编译器会选择符号的定义。这时b.c中函数f()内对变量a的操作实际上操作的是a.c中的全局变量a。所不同的是由于在b.c总声明的变量为双精度型,所以对该变量进行赋值为0.0时,需要将由a所指向的内存空间的首地址开始的8个字节清0,而不是4个。这个时候,变量a后面的变量b的存储空间也被覆盖了。因此输出的a和b的值都是0.