C与指针-第三、四章const\extern\static

C与指针第三章重点需要掌握的是 const\extern\static 这三个修饰关键字。
第四章主要讲的是if\while\switch\for\do..while\goto等常用语句的用法,这作为基础内容,本章就不进行讲解。

const:

const关键字是一个很常用的关键字,它限定一个变量不允许被改变,产生静态作用。

定义:

const修饰的数据类型是指常类型,常类型的变量或对象的值是不能被更新的。

目的:

const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。

用法:

1.基本用法

const int a = 10;
含义:定义了一个int类型的常量a,值为1,a为只读变量,程序允许过程中不能够直接修改它的值,即编译器编译经过类型检查后,直接用10在编译时替换,这使得编译器编译const常量过程中,少了一步存储与读内存的操作,提高了效率

2.指针

int b = 10;
1)const int a =&b;
2)int const
a = &b;
3)int const a = &b;
含义:
1)表示指针所指向的对象是只读的(
a 只读),a指向的内容不能够通过a改变

a = a +1; //错误,*a为只读,不能被赋值

2)与1)完全相同
3)表示指针指向是常量,不能够修改去指向其他内容

1
2
3
int c =20;
a = &c; //错误,a为只读,不能指向其他内容
*a = *a +1; //正确, *a不为只读

3.函数

1)修饰函数参数
void foo(const int a);
含义:传进来的a为只读,不能被修改
void foo(const int a);
含义:传进来的
a 为只读,不能被修改,同上用于把数据作为参数传进来,函数只能读取这个指针的内容,当函数返回内部的类型时,已经是一个数值,当然不可被赋值更新,因此这种写法无意义

2)修饰函数返回值
const int foo();
含义:返回值为const类型,指返回的原函数里的变量初值不能被修改

4.类型检查

const的值只能赋值给const对象,不能赋值给非const对象,只能强制类型转换才可以

1
2
3
const int b =10;
int *a = &b; //错误,a为非const对象,b为const对象
int *a = (int *)&b; //正确,强制类型转换

extern:

定义:

extern可置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量或函数时,在其它模块中寻找其定义。通过这种行为它告诉编译器:该变量/函数的定义已经存在在某个地方了,让编译器到其他的模块去寻找它的定义。

用法:

extern用在变量声明中常常有这样一个作用:你要在.c文件中引用另一个文件中的一个全局的变量,那就应该放在.h中用extern来声明这个全局变量。
在定义函数的时候,这个extern可以被省略,函数的默认定义就是extern类型

extern int a;//声明一个全局变量a ,这是一个声明,只有这样写,才能被其他的C调用

int a; //定义一个全局变量a ,这是一个定义,这不能被其他C调用

extern int a =0 ;//定义一个全局变量a 并给初值。一旦给予赋值,一定是定义,定义才会分配存储空间。

i nt a =0;//定义一个全局变量a,并给初值,
声明之后你不能直接使用这个变量,需要定义之后才能使用。

static:

static内容参考了
keyeagle的《C语言static分析》
adriano119的《static用法总结》

一个进程在内存中的布局入下图所示:

|        栈区     |
------------------
| 堆栈增长区  |
------------------
|       堆区       |
-----------------
|      其他段     |
-----------------
|        .bss段      |
-----------------
|        .data段     |
-----------------
|        .text段     |
==========

其中.text段保存进程所执行的程序二进制文件,.data段保存进程所有的已初始化的全局变量,.bss段保存进程未初始化的全局变量(其他段中还有很多乱七八糟的段,暂且不表)。在进程的整个生命周期中,.data段和.bss段内的数据时跟整个进程同生共死的,也就是在进程结束之后这些数据才会寿终就寝。

一般程序的由malloc/new产生的动态数据存放在堆区,函数内部的自动变量存放在栈区,全局变量和static变量放在.data段内(已初始化)或.bss段内(未初始化),但是它只在定义它的源文件内有效,其他源文件无法访问它

1、[静态全局变量]

//在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量。
静态全局变量有以下特点:
1)该变量在全局数据区分配内存;
2)未经初始化的静态全局变量会被程序自动初始化为0(自动变量的值是随机的,除非它被显式初始化);
3)静态全局变量在声明它的整个文件都是可见的,而在文件之外(extern)是不可见的;
定义全局变量就可以实现变量在文件中的共享,但定义静态全局变量还有以下好处:

1)静态全局变量不能被其它文件所用;
2)其它文件中可以定义相同名字的变量,不会发生冲突;

示例:
test1.c中,静态全局变量ch,只能在test1.c中使用,其他c文件不能使用

1
2
3
4
5
6
7
8
9
10
11
static  char *ch = "Hello World!";
void printstr()
{

printf("%s\n",ch);
}

test2.c
int main(void)
{

printf("%s\n",ch); //这里会报错,因为这个ch为test.c中的全局变量,只能在test1.c中使用
}

2、[静态局部变量]

在局部变量前,加上关键字static,该变量就被定义成为一个静态局部变量。

在函数体内定义了一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体,系统就会收回栈内存,局部变量也相应失效。每次调用这个局部变量在栈上的位置都不一定相同。如果我们想再两次的调用期间保留这个局部变量,就变的不可靠,一种方法使定义全局变量,另一个版本是使用静态局部变量

静态局部变量保存在全局数据区,即.data段或.bss段,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值。

静态局部变量有以下特点:

1)该变量在全局数据区分配内存;
2)静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;
3)静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;
4)它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;

3、静态函数

在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。

定义静态函数的好处:

1)静态函数不能被其它文件所用;
2)其它文件中可以定义相同名字的函数,不会发生冲突;

Tianger Ge wechat
如果您喜欢这篇文章,欢迎扫一扫我的微信公众号!