为了有效地完成数据存储任务,需要对存储器做如下处理:
1 划分:以字节(8个位bit,对应8个开关晶体管,0或1)为单位将存储器划分为一系列的存储单元。
2 编址:以线性方式给每个存储单元赋予唯一的存储地址,可以随机访问。
3 数据存储约定:数据以二进制形式放入存储空间,需要约定数据的存储空间大小、存储空间地址、数据编码和解码方式以及字节排序方式。如一个基本类型需要多字节时,用大头地址还是小头地址做为数据的地址?
3.1 数据的编码和解码方式
I 以补码方式存储整数;
II 通过ASCII编码方式存储字符;
III 以real-4或real-8方式存储浮点数(实数或小数);
3.2 大头还是小头,按理说只要统一约定就好,但是Intel公司的机器多采用小头方式,IBM、Sun等公司采用大头方式。一般情况下,可以不考虑字节排序方式的问题,但是在针对网络应用编写程序时,就必须关注使用哪种字节排序方式,这是因为网络程序通常需要在不同类型的机器之间交换数据。
为什么是8个bit为一个byte做为最小(基本)的存储单元呢?有两个原因使8显得很特殊。首先,8是2的3次方。由于计算机在最底层使用的是二进制位,而每一位只有两个可能的值,所以2的乘方用起来比10的乘方更方便。其次,需要8位(1个字节)才能对一个字符(比如一个英语字母或其他键盘符号)进行编码。
下面的变量声明和定义就暗含了上面全部的内容。
double PriceOfRice;
数据=数据规格(类型)+数据地址(变量名)数据规格=存储空间大小+编码和解码方式+可接受的运算处理(一个变量对应两个值:地址值与数据值)如果数据值也存储的是一个地址值(或解析为地址),则这样的变量称为指针变量double* p;
1 在内存中开辟一个8个字节的内存单元,可以通过sizeof(double)得到字节数;
2 该段内存单元的地址用PriceOfRice来表示;
3 此时的值是一个随机值,因为每个字节的每个位都是随机的0或1。如此时用代码cout<
另外,PriceOfRice的取名有诸多要求和考究,例如,不能使用关键字,不能用数字开头,如建议能见名知义,通过名字而不是通过注释去了解其含义。
给变量赋值:
PriceOfRice =3.18;
3.18是字面量,属于代码部分,不可寻址,3.18按real-8的编码方案编码(一串01)后放到PriceOfRice对应的内存空间(每个比特或0或1)。
字面量写法:
浮点型字面量也可以写成.46、1.e20、2.3f、123e12、1.e4L、-.34e-2f;
整形字面量:157、-0655、0xFE、-0x1UL;
字符型字面量:'C'、'ab'、'$'、''、'x61'、L'中'、L'a';
布尔型字面量:true、false;
字符串型字面量:"C++ programming"、L"abc"、"x41x42x43"(ABC);
除了字符串型字面量,其它字面量都不可寻址,字符串型字面量存储在被分配的内存空间的数据段。
另外,两行代码写到一起:double PriceOfRice =3.18;
表示变量声明、定义、初始化同时完成。
关于初始化的内容,请见:《C++|变量、对象、对象成员初始化的一些细节》。
对于代码:PriceOfRice = PriceOfRice *1.1
表示右边的PriceOfRice表示取数据值,乘以1.1,按double的编码方案编码后放到左边的PriceOfRice对应的内存单元。
C++左值和右值的概念:左值表示一种可以定位的存储空间,右值表示从存储空间中临时读取的数据值。左值可以做右值,右值不能用做左值。
而乘法运算符*则表示了double这种类型可接受的运算处理,如double就能不使用取余运算符%,而指针类型一般不会使用*来做运算(指针一般用其做解运算)。
下面是一个关于整数编码的小实例:
#include using namespace std;int main(){ unsigned long unl = -0x1UL; unsigned long ul = 0x1UL; long l = -0x1L; cout<
另外,double PriceOfRice;写在不同的位置,或者前面有诸如static、external等不同的限定词,决定了其有不同的作用域和存续期,同时也确定了其存储到被分配给程序的一块内存空间中不同的区域(栈区、全局区静态区等)。
变量规定了名字和数据类型的存储空间,执行程序就是促使变量的存储空间状态发生变化,并达到预期状态的。因此,编程时应该能够随时在大脑中描绘出变量相对应的存储空间状态,称为存储空间映像。
下图是关于数据类型、修饰符、长度、编码方案、用于赋值的字面量的一个综述:
如果是数组变量、结构体变量或对象,其存储空间是如何映像的呢?本质也是通过变量名或对象名来确定其对应的内存空间的首地址,通过成员各自的长度或统一分配的长度来映像。
对于数组,就是首元素的地址,通过整数偏移来确定分量的地址。
结构体、对象的数据成员都是集中存储在一起的,确定了首地址,也就能按其成员类型给予的空间大小顺序找到各成员的地址。不像数组通过整数(下标)来偏移,结构体、对象是从结构体、对象名称开始,通过引用数据成员变量名来进行偏移的。
一个结构体变量或对象的成员数据也是顺序存储在一起的,或者是按各自长度存储,或者编译器基于效率因素增加一些额外字节以使存储边界对齐。
-End-