欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C语言进阶:const和volatile

程序员文章站 2022-04-12 20:05:29
const只读变量。 const修饰的变量是可读的,本质上是变量。 const修饰的局部变量在栈上分配空间; const修饰的全局变量在全局数据区分配空间; const只在编译期有用,在运行期无用。...

const只读变量

const修饰的变量是可读的,本质上是变量。

const修饰的局部变量在栈上分配空间;

const修饰的全局变量在全局数据区分配空间;

const只在编译期有用,在运行期无用。

所以,本质上来讲,const修饰的其实不是常量,而是一个不能被改变的变量(不能出现在赋值符号的左边)。

在现代编译器中,修改const全局变量将导致程序崩溃。

注意:标准c语言编译器不会将const修饰的全局变量存储于只读存储区,而是存储于可修改的全局数据区,其值依然可以改变。

观察下面代码,体会const的作用:

#include

const int g_cc = 5; //全局变量存储于只读存储区

int main()
{
	const int cc = 1;  //在栈上分配空间
	
	printf("%d\n", cc);
	
	//cc = 2;
	
	int *p = (int *)&cc;
	
	*p=3;
	
	printf("%d\n", cc);
	
	printf("g_cc = %d\n", g_cc);
	
	//g_cc = 6; //error
	
	p = (int *)&g_cc;
	
	*p=7;  //在gcc中报段错误  (在bcc中不报错)
	
	printf("g_cc = %d\n", g_cc);
	
	return 0;
}

在不同的编译器中,对于全局的const变量,编译效果不同。

在现代的编译器中,对于const修饰的全局变量, 会将其编译进只读存储区,一旦出现对只读存储区的修改,就会直接报错。(早期的支持标准c的编译器支持对const修饰的全局变量通过指针进行修改)

但标准c语言只是将其定义为只读,不涉及存储区。

const修饰的static将会在只读存储区中存储。

#include 

const int g_array[5] = {0};

void modify(int* p, int v) //不能使用void* p,是左值
{
	*p = v;
}

int main()
{
	int const i = 0;
	const static int j = 1;
	int const arry[5] = {0};
	
	modify((int*)&i, 2);
	//modify((int*)&j, 3);  //error
	modify((int*)&array[0], 4);
	//modify((int*)&g_array[0], 5); //error
	
	printf("%d\n", i);
	printf("%d\n", j);
	printf("%d\n", array[0]);
	printf("%d\n", g_array[0]);
	
	return 0;
}

const 修饰函数参数表示函数体内不希望改变参数的值;

const 修饰的函数返回至表示返回值不可改变,多用于返回指针的情形。

观察下面代码,体会const修饰参数和返回值:

注意:c语言中的字符串字面量存储于只读存储区,在程序中需要使用const char*指针。

#include 

const char* f(const int i)
{
	i = 5;  //error   test.c:5: error: assignment of read-only location ‘i’
	
	return "will willing";  //字面量
}

int main()
{
	const char* p = f(0);    //注意此处对 p 的声明为const char*
	
	printf("%s\n", p);
	
	p[5] = '_';  //error  test.c:16: error: assignment of read-only location ‘*(p + 5u)’
	
	printf("%s\n", p);
		
	return 0;
}

linux下使用gcc编译代码,报错信息如代码注释所示。

现代的编译器在每次操作时,都会去优化操作,避免每次去内存中存取数据。

volatile可理解为“编译器警告指示字”,它告诉编译器必须每次去内存中取变量值。

volatile注意修饰可能被多个线程访问的变量,也可以修饰可能被未知因素更改的变量。

int obj=10;

int a=0;  int b=0;

a = obj;
sleep(100);  ????????????????//编译器在编译的时候发现obj没有被当做左值使用,
????????????????????????????//因此会“聪明”的直接将obj替换成10,而把a,b都赋值为10.
b = obj;

可是在实际的程序运行中,比如多线程或者出现中断,会在sleep(100)中修改obj的值,这个时候b的值就会与预期不一样。

const volatile int i=0;

上述语句中变量i具有什么样的特性?

存储在内存中(不让编译器优化);不能做左值。

编译器如何改变这个变量?

通过指针。

小结:

const使得变量具有只读属性,不能定义真正意义上的常量。(enum可以)

const将具有全局生命期的变量存储在只读存储区。

volatile强制编译器减少优化(多用于嵌入式和多线程),必须每次都从内存中取值。