-------------------------------------const--------------------------------
const关键字,很多人想到的可能是const常量,其实关键字const并不能把变量变成常量!
在一个符号前加上const限定符只是表示这个符号 不能被赋值。也就是它的值对于这个符号来说是只读的,但它并不
能防止通过程序的内部(甚至是外部)的方法来修改这个值。也就是说 const变量是只读变量,既然是变量那么就可以
取得其地址,然后修改其值。看来const也是防君子不防小人!
const 使用情况分类详析
1、const的普通用法
const int n = 20 ;
意思很明显,n是一个只读变量,程序不可以直接修改其值。
这里还有一个问题需要注意,即如下使用:int a[n];在ANSI C中,这种写法是错误的,因为数组的大小应该是个常量,而n只是一个变量。
2、const用于指针
const int* p1 ; //指针指向的内容不能用指针改变
int const *p2; //指针指向的内容不能用指针改变
int* const p3 ; //指针的指向不能改变
const int *const p4 ; //指针的指向不能改变,同时指针的内容不能通过指针改变
进一步解析:前面两种p1、p2指针 指向的对象是只读的。const是一个左结合的类型修饰符,它与左侧的类型一起为一个类型修饰符,所以,int const 限定*p2,(p1也是同样的)。int* const 限定p3,而不是限定*p3。
这里有一个简便的区分方法:“就近原则”, 去掉类型后,const离哪个(‘*’,p(指针))近就修饰哪个
3、const用于函数的地址传递参数
void fun(const int *p);
这种形式通常用于在数组形式的参数中模拟传值调用。也就是相当于函数调用者声称:"我给你一个指向它的指
针,但你不能去修改它。"如果函数编写者遵循了这个约定,那么就相当于模拟了值传递。这也是const最有用之处
了:用来限定函数的形参,这样该函数将不会修改实参指针所指的数据。这里注意了,是函数不应该去修改而不是不
能修改。
4、const用于限定函数的返回值
const int fun();
上述写法限定函数的返回值不可被更新,当函数返回内部的类型时,已经是一个数值,当然不可被赋值更新,所
以,此时const无意义,最好去掉,以免困惑。当函数返回自定义的类型时,这个类型仍然包含可以被赋值的变量成
员,所以,此时有意义。
const用法:
定义常量,修饰指针、函数的输入参数和返回值,简单说const表示只读的意思,本质上来说它只是在全局数据
段或者栈中定义的是一个只读的常量,不是真正位于字符串常量区。Const的目的是为了产生高质量的代码,提高代
码的可读性,同时保护好不能被任意改变的内存,从而降低Bug产 生的概率。
-------------------------------------extern------------------------------------------------
基本解释及用法
extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。通过这种行为它告诉编译器:该变量/函数的定义已经存在在某个地方了,让编译器到其他的模块去寻找它的定义。此外extern也可用来进行链接指定。
也就是说extern有两个作用:第一个,当它与"C"一起连用时,如: extern "C" void fun(int a, int b);则告诉编译器在
编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的。
第二,当extern不与"C"在一起修饰变量或函数时。
如在头文件中:extern int i; //它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可
以在本模块或其他模块中使用,记住它是一个声明不是定义!
-------------------------------------static------------------------------------------------
当一个进程的变量被声明为static之后,它的中文名叫静态变量。 使用时可以改变其值。它只在定义它的源
文件内有效,其他源文件无法访问它,程序开始时分配空间,结束时释放空间,默认初始化为0。所以,普通变
量穿上static外衣后,它就变成了新娘,已心有所属,只能被定义它的源文件(新郎)中的变量或函数访问。
static用法分析
1、修饰变量
A、修饰局部变量
一般情况下,对于局部变量是存放在栈区的,并且局部变量的生命周期在该语句块执行结束时便结束了。但是如
果用static进行修饰的话,该变量便存放在静态数据区,其生命周期一直持续到整个程序执行结束。但是在这里要注
意的是,虽然用static对局部变量进行修饰过后,其生命周期以及存储空间发生了变化,但是其作用域并没有改变,
其仍然是一个局部变量,作用域仅限于该语句块。
在用static修饰局部变量后,该变量只在初次运行时进行初始化工作,且只进行一次。
例如:
#include<stdio.h>
void funTest()
{
static int a = 1;
a++;
printf("%d ", a);
}
int main()
{
funTest();
funTest();
return 0;
}
输出结果: 2 , 3
解析:说明第二次电泳funTest函数时,a已经有了值(为2),并且没有进行初始化赋值,直接进行自增运算,所以
得到的结果为3.
另外,对于静态局部变量如果没有进行初始化的话,对于整形变量系统会自动对其赋值为0,对于字符数组,会自动赋值为'\0'。
B、修饰全局变量
静态全局变量和其他的全局变量的存储地点并没有区别,都是在.data段(已初始化)或者.bss段(未初始化)内,但是它只在定义它的源文件内有效,其他源文件无法访问它。
例如:
Test.h
#include<stdio.h>
void PrintStr();
test1.c 在这里定义一个全局变量 ,看是否其他源文件是否能访问
#include"Test.h"
static int a = 0;
void PrintStr()
{
printf("%d ", a);
}
#include"Test.h"
int main()
{
PrintStr();
printf("%d ", a);
}
编译,报错如下:
error C2065: “a”: 未声明的标识符
如果将 test2.c 修改成这样:
#include"Test.h"
int main()
{
PrintStr();
// printf("%d ", a);
}
编译成功,完美运行
解析: test1.c中的a就是一个静态全局变量,它可以被同一文件中的 PrintStr调用,但是不能被不同源文件中的test2.c调用。
2、修饰函数
在函数前面添加static 后使得函数的访问域仅仅为其所定义的函数。
测试如下:
Test.h //添加两个函数,一个加上static 另一个不添加
#include<stdio.h>
static void PrintStr();
void funTest();
test1.c //在这里定义两个函数
#include"Test.h"
int a = 0;
static void PrintStr()
{
printf("%d ", a);
}
void funTest()
{
printf("%d ", a + 1);
}
test2.c //通过这个源文件,看是否能编译成功
#include"Test.h"
int main()
{
PrintStr();
funTest();
return 0;
}
编译结果: error C2129: 静态函数“void PrintStr()”已声明但未定义
将test2.c修改成这样:
#include"Test.h"
int main()
{
// PrintStr();
funTest();
return 0;
}
解析: funTest和PrintStr都是在test1.里定义,但PrintStr前面添加了ststic,限定了它的使用范围,只能在当前源文件处使用
对于 const 、extern、static 还需要添加的,希望各位指点