第十四章-static和extern
- 这两个关键字作用的对象:
- 函数
- 变量
static和extern 对函数的作用
- 如果一个程序中有多个源文件(.c),编译成功会生成对应的多个目标文件(.obj),这些目标文件还不能单独运行,因为这些目标文件之间可能会有关联,比如a.obj可能会调用c.obj中定义的一个函数。将这些相关联的目标文件链接在一起后才能生成可执行文件。
- 内部函数与外部函数:
- 外部函数:如果在当前文件中定义的函数允许其他文件访问、调用,就称为外部函数。
- C语言规定,不允许有同名的外部函数。
- 默认情况下所有的函数都是外部函数.
- 内部函数:如果在当前文件中定义的函数不允许其他文件访问、调用,只能在内部使用,就称为内部函数。
- C语言规定不同的源文件可以有同名的内部函数,并且互不干扰。
- 外部函数:如果在当前文件中定义的函数允许其他文件访问、调用,就称为外部函数。
- 编译与链接:
- 编译: 所谓编译,就是单独检查每个源文件的语法是否合理,并不会检查每个源文件之间的关联关系,一个源文件编译成功就生成一个目标文件。
- 所谓链接,就是检查目标文件的关联关系,将相关联的目标文件组合在一起,生成可执行文件。
- 如果调用一个函数,而之前并未声明,即只有定义,没有声明
- 这个在标准C编译器里面会报错的,但是在Xcode中只是个警告
- 只有声明没有定义
- 程序是可以编译成功的,在链接的时候才会检测这个函数存不存在,也就是有没有被定义。
- 多文件开发
- 我们知道,当使用多文件开发时,对方只需要提供.h文件(内部放了全部的函数声明),我们导入即可使用其文件的函数.
extern与函数
- 在定义函数时,如果在函数的最左边加上关键字extern,则表示此函数是外部函数,可供其他文件调用。C语言规定,如果在定义函数时省略extern,则隐含为外部函数。
- 在一个文件中要调用其他文件中的外部函数,则需要在当前文件中用extern声明该外部函数,然后就可以使用,这里的extern也可以省略。
static与函数
- 在定义函数时,在函数的最左边加上static可以把该函数声明为内部函数(又叫静态函数),这样该函数就只能在其定义所在的文件中使用。如果在不同的文件中有同名的内部函数,则互不干扰。
- static也可以用来声明一个内部函数
代码举例
在main.c中调用one.c中定义的test函数。
one.c文件
#include <stdio.h>
// 声明一个内部函数
static void test2();
// 完整地定义一个外部函数
/*
extern void test()
{
printf("调用了test函数\n");
}*/
// 默认情况下,所有的函数都是外部函数,所以可以省略extern
void test()
{
printf("调用了test函数\n");
test2();
}
// 定义一个内部函数
static void test2()
{
printf("调用了test2函数\n");
}
one.h文件
#ifndef _ONE_
#define _ONE_
//extern void one(); extern可以省略
//外部函数
void test();
//内部函数
static void test2();
#endif
main.c文件
/*
// 完整地声明一个外部函数
// extern可以省略
//extern void test();
void test();
void test2();
*/
//上面用导入头文件代替
#include "one.h"
int main()
{
//调用成功
test();
//编译成功,连接会报错,因为one.c中test2为内部函数
test2();
return 0;
}
//不能重复定义外部函数
//void test()
//{
//
//}
//可以重复定义内部函数
//static void test2()
//{
//
//}
static和extern 对变量的作用
- 这里extern其实没多大用,只理解static即可以
- static修饰全局变量->内部变量
- static修饰局部变量->延长生命周期
static和extern 对全局变量的作用
- 全局变量分2种:
- 外部变量:定义的变量能被本文件和其他文件访问
- 默认情况下,所有的全局变量都是外部变量
- 不同文件中的同名外部变量,都代表着同一个变量
- 外部变量:定义的变量能被本文件和其他文件访问
- 内部变量:定义的变量只能被本文件访问,不能被其他文件访问
- 不同文件中的同名内部变量,互不影响
extern对全局变量的作用
- 声明一个外部变量
static对全局变量的作用
- 定义一个内部变量
main.c文件
#include <stdio.h>
void test();
// 定义一个外部变量
// 这么多个a都是代表同一个a : one.c中的a/当前文件所有的a;
//int a;
//int a;
//int a;
// 声明一个外部变量(只是声明,还没有定义,要想真正使用,还得定义)
//extern int a;
// 定义一个内部变量,跟one.c中的b无关
static int b;
int main()
{
//并不会影响one.c中b的值
b = 10;
//声明一个外部变量a(也可以写在函数内部,但是此时的a可是外部变量属于全局变量)
//这里可不是修饰局部变量哦!!!
extern int a;
//可以使用,因为已经声明,但是没有定义,编译不会报错,连接会报错,必须有定义,跟函数一样
a = 10;
//打印 a 为10,b为0
test();
//打印a为20;
printf("a的值是%d\n", a);
return 0;
}
//定义一个外部变量(没有这一句连接会报错!!!)
int a;
one.c文件
#include <stdio.h>
int a;
static int b;
void test()
{
printf("b的值是%d\n", b);
printf("a的值是%d\n", a);
a = 20;
}
static和extern 对局部变量的作用
- extern 不针对局部变量作用
static修饰局部变量
- 延长局部变量的生命周期:程序结束的时候,局部变量才会被销毁
- 并没有改变局部变量的作用域
void test(){
int a = 0;
a++;
//每一次调用都是1
printf("a的值是%d\n", a);
static int b = 0;
b++;
//每一次调用,都会在上次的基础上+1
printf("b的值是%d\n", b);
}
int main(){
for (int i = 0; i<100; i++) {
test();
}
return 0;
}