文章目录
- 作用域、可见性
- 函数作用域
- 文件作用域
- 语句块作用域
- 函数原型作用域
- 标识符的存储类型
- 全局对象与函数
- 静态对象与函数
- 局部对象
作用域、可见性
一个变量标识符只有在特定的某段儿程序区域(作用域)内才可以起作用(可见性)。
总共有四种作用域:函数作用域、文件作用域、语句块作用域、函数原型作用域
函数作用域
跳转标签(就是goto
的label)是仅有的函数作用域的标识符,使用时,会与goto
配合出现。
它不会受其他语句块儿的干扰,只要是在所处的函数里,什么地方都可以起作用。
int main() {int count = 3;HELLO_LABEL:puts("hello \n");if(-- count > 0) {goto HELLO_LABEL;}switch(count) {case 1: count = 0; break;case 0: count = 3;SWITCH_INNER_LABEL:printf("inside switch! \n");break;default :break;}if(-- count > 0) {goto SWITCH_INNER_LABEL;}
}
SWITCH_INNER_LABEL尽管是在switch的语句块儿里定义的,但还是可以从外部访问到。
文件作用域
文件作用域,即从它声明开始到文件结束都是可见的。
在所有函数外定义的标识符称为全局标识符,比如全局变量、函数声明、头文件中的标识符、宏定义。
#include <stdio.h> // 头文件中的
#define macro 10 // 定义的宏变量
int global_variable = 10; // 全局变量
void fun(void); // 函数声明中的函数int main() {/* do something */return 0;
}void fun(void) {/* do something */return ;
}
语句块作用域
声明出现在一个语句块儿里、或是函数定义的形参列表中。
-
当标识符的作用域完全相同时,不允许出现相同的标识符名,而当标识符有不同作用域时允许标识符同名。
-
如果是作用域嵌套的情况下,如果内层和外层的作用域声明了同名的标识符,那么在外层作用域中声明的标识符对于该内层作用域时不可见的。
int main() {int i = 0;{int i = 2; // 这里内部的i起作用,可见printf(“i2 = %d”, i); // i的值为2i += 2; }i ++; // 这里外部的i起作用,可见printf(“i1 = %d”, i); // 1
}
函数原型作用域
就是在函数原型声明里的标签
int fun(int argc, char** argv);
比如这里的argc
和argv
???
标识符的存储类型
全局对象与函数
extern声明的对象,或者缺省(无extern或static修饰)的函数具有外部链接。
能够被extern修饰的函数或对象是全局的,只要提前声明,则该对象和函数可在所有文件内可见。
在test.c中
extern int a;
void test(void) {a = 10;
}
在main.c中
#include <stdio.h>
extern void test(void)int a; // 全局变量a的声明
int a = 10; // 全局变量a的初始化(声明+定义)int main() {extern int a;/* 只不过在main函数的语句块儿内重新声明了一下a,声明成了(与全局变量a同名的)只具有语句块儿作用域的局部对象,正好将全局变量a覆盖掉了,但是这句话写和没写一个样 */printf("a = %d \n");return 0;
}
静态对象与函数
在文件作用域中声明的对象或函数,并且由static修饰。
静态对象或函数只能在该文件的上下文中可见,不会与其他文件中的对象或函数冲突。
#include <stdio.h>
static int a = 10;
static void fun(void);int main() {return 0;
}static void fun(void) {/* do something */return ;
}
局部对象
声明为函数形参或者在一个语句块儿作用域中(未用static或extern)声明的对象。
局部对象,只要离开了声明它的语句块儿,它就失去了可见性(生命周期结束)。
在古早的C语言中,会使用auto或register声明一个局部变量。但C语言更新迭代到现在,这两个关键字几乎被废弃了。auto会显式地告诉编译器该变量是局部变量,register会建议编译器最好让变量存储在寄存器里(当然C编译器也不一定听从建议~~)