左值与右值
2003-5-3
在程序设计中,左值与右值是一个基本问题。任何变量与函数名都有左值和右值。简单的说左值是变量所代表的内容在内存中存放的地址;右值则是该变量代表的内容。下面的图示形象地给出左值与右值的关系。
在上图中,变量x代表存放在内存中的一个字符‘A’,该字符便是变量x的右值,其左值如图所示。实际使用过程中,直接对变量x操作,实则对其右值——字符‘A’进行操作。要取得变量x的左值,需要使用取址符号‘&’,即通过&x来取得x的左值。
程序执行的过程,是不断改变变量的左值和右值的过程。
从声明变量的那一刻起,系统便要为该变量设定初始值——包括左值和右值。左值的设定——即变量在内存所处的位置,要根据变量的声明类型、声明方式和声明时所处程序的位置来决定。全局变量和静态变量都存放与“全局变量”区域,见下图。(注:该图摘自《C语言大全(第四版)》(赫伯特●希尔特),我怀疑该图过于简略,画得不太妥当。怀疑原因来自文后的例子。)
一切局部变量都存放在栈区域。虽然在程序执行过程中申请的内存在堆内分配,但指向分配内存的变量还是存放在栈上。
局部变量的初始右值不确定,而全局变量和静态变量的初始右值自动设置为零。
理解变量的左值与右值,对理解指针的声明、初始值以及使用方法都有极大的帮助。
一个例子:
#include <stdio.h>
float f;
void main()
{
float *x, *y;
static float *z;
const float g = 1.2;
register int r;
int *n = new int [1];
printf("the address of *x viz. the value of variable x is: %d\n", x);
printf("the address of *y viz. the value of variable y is: %d\n", y);
printf("the address of *z viz. the value of variable z is: %d\n", z);
printf("the address of *n viz. the value of variable n is: %d\n", n);
printf("the address of x is: %d\n", &x);
printf("the address of y is: %d\n", &y);
printf("the address of static z is: %d\n", &z);
printf("the address of new n is: %d\n", &n);
printf("the value of f is: %d\n", f);
printf("the address of global f is: %d\n", &f);
printf("the value of g is: %f\n", g);
printf("the address of const g is: %d\n", &g);
printf("the value of r is: %d\n", r);
printf("the address of register r is: %d\n", &r);
}
编译器:
g++(Dev-C++ 4.9.6.0)
运行平台:
WIN2000
运行结果:
the address of *x viz. the value of variable x is: 2293600
the address of *y viz. the value of variable y is: 2
the address of *z viz. the value of variable z is: 0
the address of *n viz. the value of variable n is: 4598752
the address of x is: 2293592
the address of y is: 2293588
the address of static z is: 4227080
the address of new n is: 2293580
the value of f is: 0
the address of global f is: 4227072
the value of g is: 1.200000
the address of const g is: 2293584
the value of r is: 4598752
the address of register r is: 2293564
几点分析:
1、全局变量f和静态变量z存放在同一区域,该区域位于高址地带。
2、局部变量x、y、r、n存放于同一区域。
3、全局变量和静态变量的右值都自动初始化为零。对于指针z这意味着它指向NULL。
4、局部变量的自动右值不确定,如x、y和r。
5、对变量的内存映像图的改动,如下图:
2003-5-14修改:
例子基本不变,仅把地址显示格式改为16进制。
硬件环境不变(同一台计算机)。
编译器:
gcc (GCC) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
运行平台:
Linux 2.4.20-8(Red Hat 9.0)
运行结果:
the address of *x viz. the value of variable x is: 40015360
the address of *y viz. the value of variable y is: 42130a14
the address of *z viz. the value of variable z is: 0
the address of *n viz. the value of variable n is: 80498c8
the address of x is: bffff524
the address of y is: bffff520
the address of static z is: 8049870
the address of new n is: bffff514
the value of f is: 0
the address of global f is: 80498d4
the value of g is: 1.200000
the address of const g is: bffff51c
the value of r is: -1073744600
the address of register r is: bffff518
思考:
1、在Linux平台,从结果看到的变量的内存映像排列与赫伯特的描述是一致的。
2、在Linux平台,每次运行该程序得到的结果皆不一致,即同一变量的地址在每次程序执行时都会发生改变。与此相反,在Windows平台,程序无论被执行多少次(笔者已执行10次以上),结果皆一致。
3、从各自的结果可以看到Windows平台的变量地址明显要比Linux平台的变量地址小,而且前者堆与栈之间的跨度远不及后者的大。因此我猜测前者显示的是变量的实地址(即真正的内存地址)。至于后者,显然是采用了虚地址。
本文地址:http://com.8s8s.com/it/it29273.htm