今天继续学习c语言语法,相对之前的知识而言,这次的知识就比较重要了,算是C语言的核心基础了,所以得好好学它,下面正式开始:

存储类别: 它指定了变量生存期(时间)与作用域(空间)

程序结构_标识符


对于下面这个函数:

程序结构_全局变量_02


程序结构_全局变量_03


程序结构_作用域_04


程序结构_标识符_05

程序结构_全局变量_06

运行结果:

程序结构_全局变量_07

解析:

静态变量,只分配一次内存,离开作用域的时候,生存期并未结束,它的生存期是整个程序的执行期[这也说明作用域和生存期是不一样的],所以上面执行了两次的结果累加了。

另外,需要注意:

程序结构_作用域_08




 程序结构_全局变量_09

下面有两个C文件:

程序结构_标识符_10

test.c的内容:

程序结构_全局变量_11

1_9.c的内容:

程序结构_标识符_12

这时编译两个c到一个可执行文件:

程序结构_作用域_13


解决之道,就是将test.c的文件中的全局变量声明为static的,因为static修饰全局变量,它的作用域只限本文件中,对于1_9.c是看不到的:

程序结构_标识符_14

这时编译就成功了:

程序结构_标识符_15


程序结构_作用域_16

这个依照静态全局变量的,就很容易理解了:

test.c:

程序结构_全局变量_17

1_9.c:

程序结构_全局变量_18

这时编译:

程序结构_作用域_19


将test.c的函数声明为静态的,这时就成功了:

程序结构_全局变量_20

程序结构_作用域_21


提示:不管是局静态局部变量还是静态全局变量生存期是整个程序执行期


程序结构_标识符_22


修饰变量:

还是两个.c文件:

test.c声明一个全局变量:

程序结构_标识符_23


而如果1_9.c想直接用这个变量会怎么样呢?

程序结构_作用域_24


程序结构_全局变量_25


那如果就是想用test.c定义的全局变量呢,这时extern就派上用场了:

程序结构_全局变量_26

再次编译,这回就成功了:

程序结构_作用域_27


修饰函数:

test.c:

程序结构_全局变量_28

1_9.c:

程序结构_作用域_29  

编译貌似没有报错:

程序结构_全局变量_30

但如果把警告打开再编译一下: 程序结构_作用域_31

所以,并非直接能调用其它文件声明的全局函数,而还得用上extern来解决: 程序结构_标识符_32

这时再编译:

程序结构_全局变量_33  

实际上,对于函数,extern关键字可以省略,但是变量则不行,如下: 程序结构_作用域_34程序结构_作用域_35  

另外,还有两个修饰关键字,可以了解一下: 程序结构_标识符_36  

标识符的五种作用域[了解下既可!]:

程序结构_全局变量_37   程序结构_全局变量_38程序结构_全局变量_39

①只能在函数体中引用 ②标签号(用于goto)是唯一具有函数作用域的标识符 程序结构_标识符_40   程序结构_全局变量_41

①在程序块中声明的标识符具有块作用域,块作用域开始于声明处,结束于程序块的右花括号 很容易理解,平常只是我们没将它理论化而已:

 程序结构_标识符_42

程序结构_标识符_42程序结构_标识符_44  

②函数的形式参数、函数的局部变量、在复合语句中声明的变量具有块作用域  程序结构_作用域_45

③如果外层块和内层块有相同名字的变量,外层说明会被内层说明屏蔽(最近嵌套原则)   程序结构_作用域_46

在一个程序文件的所有函数定义之外定义的标识符,则该标识符具有全局作用域,即该标识符在整个程序包括的所有文件中都有效,都是可见的,都是可以访问的。 也就是extern全局变量, extern函数   程序结构_全局变量_47

在函数外面定义的标识符并且用static修饰,能够被从标识符说明到文件结束之间的所有函数引用 也就是static全局变量、static函数定义或函数原型   预处理指令:程序结构_全局变量_48   程序结构_全局变量_49  

下面有三个文件:test.c、test.h、1_9.c,来演示一下预编译指今的用法: 程序结构_标识符_50

它们的关系如下:

程序结构_全局变量_51

test.h:

// ifndef defing endif 是为了防止重复包含头文件
#ifndef _TEST_H_
#define _TEST_H_

void fun(void);//声明了函数


#endif /* _TEST_H_ */


test.c:

#include <stdio.h>

void fun(void)
{
printf("hello fun test ...\n");
}


1_9.c:

#include <stdio.h>
#include "test.h"//包含头文件

int main(void)
{
fun();
return 0;
}


运行:

程序结构_作用域_52

将函数放到.h里面声明的好处,可以复用,需要调用的.c文件中只需包含一下.h文件既可,另外,全局变量最好不要定义.h头文件中,而应该放到.c文件中

为了说明这个原因,再增加一个.c文件,如下:

程序结构_作用域_53

里面啥都不做,只包含头文件:

程序结构_全局变量_54

这时在.h中声明一个全局变量,注意:不是static的:

test.h:

程序结构_作用域_55

我们知道1_9.c也包含了test.h头文件,也就是test.h现在被test2和1_9.c所包含,这时编译:

程序结构_作用域_56

这也就是为什么全局变量最好不要定义.h头文件中的原因了,当被多个文件包含时就会出现上面的错误,虽说在.h中已经有重复定义的判断了,那怎么解决呢?

解决方法如下:

程序结构_作用域_57

test.c:

程序结构_作用域_58


test.h:

程序结构_全局变量_59

这时,其它都不用变,test.h还是被两个文件同时包含,再编译就成功了:

程序结构_标识符_60

条件编译:

程序结构_标识符_61

下面举一个在程序中使用条件编译的用法:

程序结构_作用域_62

默认编译运行:

程序结构_作用域_63

  这时我们在文件中定义一个DEBUG宏:

程序结构_作用域_64


程序结构_全局变量_65

  另外,也可以不在程序中加入这个宏的定义,而在gcc编译时携带参数来编译出带这个宏的可执行文件: 先将宏定义从源文件去掉:

程序结构_全局变量_66程序结构_全局变量_67


程序结构_标识符_68

  好了,这次的内容就学到这,里面的东西需细细体会,这也基础知识也是助自己深入学习C很有利的因素,之后就已经到了C语言的最核心的部分了,所以需不骄不躁,一步一个脚印学习。