跟我学“数据结构”系列:用程序探索数据
摘要:
关键字
引言
在开始数据结构之前,我们先来一节基础课:“数据”
最近数十年来,计算机领域高速发展,计算机已深入到各行各业,已能处理像如文字、图形、图像、声音等代表不同属性的信息。本文从程序员观点,利用c++程序来探索计算机是如何表示和处理数据的。
适用的读者:
初级
相关性:
本文是学习后续“数据结构”课程的基础。
二进制
电脑内部为什么要用二进制呢?这是因为二进制中只有两个数,即0和1。二进制数在电气元件中容易实现、容易运算,在电子学中具有两种稳定状态以代表0和1。而需要由0和1来代表的量很多。如:电压的高和低,电灯的亮和灭,电容的充电和放电,脉冲的有和无,晶体管的导通和截止等。总之,电脑内部使用二进制,主要是为了设计和制造电脑方便。
先假定普通灯泡只有亮、灭两种状态。以灯泡为工具,我们来探析计算机中数据是如何表示的: 我们把一个灯泡称为一“位”,当有一“位”灯泡(用格子表示)的时候,能表示两个数,这两个数 0和1。
[p1.jpg]

由上图可见,一位可表示2个数;二位可以表示4个数,三位可以表示8个数,即2的3次方,4位可以表示2的 4次方个数,16位可以表示2的16次方个数,32位表示能表示2的32次方个数(0到4294967295)。
我们常说的8位机(如任天堂游戏机),16位机(如早期的286),以及32位机(最近几年的主流PC机),现在有些服务器是64位机,我们的桌面电脑也即将过渡至64位。这里说的“位数”就指在计算机系统中,一个寄存器有多少个可以表示0或1的小格子的个数。这也指整型数据类型或指针类型的位数。
表示信息的单位
位和字节:“位”是计算机中信息的最小的元素。但这个单位实在太小了,制造计算机的时候,一般会把8个“位”合在一起,称为一个字节。字节是计算机处理信息的最小单位。
、

信息表示形式
日常人们通常用十进制来表示一个数。如100分。由于计算机更容易处理二进制,用二进制表示100,二进制表示为1100100,用16表示为0x64,图解如下:
用C++程序来探索计算机数据的表示方式
代码1:
使用C++的iostream显示数据。
- //file:1esson.cpp
- //
- #include<iostream>
- #include<iomanip>
- #include<string>
- using namespace std;
- void showBytes(unsigned char* p, size_t length);
- void showUINT(unsigned int x);
- template <typename T> void showType( T x);
- template <typename T> void showTypeWithName( T x,string typeName);
- void swapUINT32(unsigned int * ptr);
- void swapUINT16(unsigned short int* ptr);
- int main(int argc, char* argv[])
- {
- cout << argv[0] << "start here." << endl;
- cout << "this program illustrates how to use iostream." << endl;
- unsigned int x = 100;
- cout << "decimal format:" << dec << x << endl;
- cout << "octal format:" << oct << x << endl;
- cout << "hexadecimal format:" << hex << x << endl;
- cout << "address is :" << &x << endl;
- cout << "sizeof (unsigned int) in my computer is :" << sizeof (unsigned int) << endl;
- cout << "sizeof (signed int ) in my computer is :" << sizeof (signed int) << endl;
- cout << "sizeof (char ) in my computer is :" << sizeof (char) << endl;
- cout << "sizeof (unsigned char ) in my computer is :" << sizeof (unsigned char) << endl;
- cout << "sizeof (short ) in my computer is :" << sizeof (short) << endl;
- cout << "sizeof (long ) in my computer is :" << sizeof (long) << endl;
- cout << "sizeof (double ) in my computer is :" << sizeof (double) << endl;
- cout << "sizeof (float ) in my computer is :" << sizeof (float) << endl;
- cout << "we are explore the unsigned int " << x << " in my compute. "<< endl;
- showUINT(x);
- cout << "we are explore more ..." << endl;
- unsigned int a = 1u;
- unsigned int b = 8u;
- unsigned int c = 65535u;
- unsigned int d = 10000u;
- unsigned int e = 4294967294u;
- showUINT(a);
- showUINT(b);
- showUINT(c);
- showUINT(d);
- showUINT(e);
- showType<unsigned int> (x);
- float f = 3.14f;
- showType<float> (f);
- showTypeWithName<float> (f,"float");
- showTypeWithName<double> (3.14,"double");
- /*
- for(unsigned int i = 0; i < e; i++)
- {
- showUINT(i);
- }
- */
- cout << "/nwe are explore byte endian" << endl;
- cout<< "before swapping byte : " ;
- x = 0x12345678; //
- cout << " x = " << hex << "0x" << x << " dec:" << dec << x<< endl;
- showUINT(x);
- swapUINT32(&x);
- cout<< "before swapping byte : " ;
- showUINT(x);
- x = 0x12345677;
- cout << " x = " << hex << "0x" << x << " dec:" << dec << x<< endl;
- cout<< "before swapping byte : " ;
- showUINT(x);
- swapUINT32(&x);
- cout<< "before swapping byte : " ;
- showUINT(x);
- x = 0x12345679;
- cout << " x = " << hex << "0x" << x << " dec:" << dec << x<< endl;
- cout<< "before swapping byte : " ;
- showUINT(x);
- swapUINT32(&x);
- cout<< "after swapping byte : " ; // thanks 岑梓源
- showUINT(x);
- return 0;
- }
- void showBytes(unsigned char* p, size_t length)
- {
- unsigned int i = 0;
- for(i = 0; i < length ; i++)
- {
- //printf(" %.2x",p[i]);
- cout<<hex<<setw(2)<<right<<setfill('0')<<(int)p[i] << " ";
- }
- cout << endl;
- }
- void showUINT(unsigned int x)
- {
- showBytes((unsigned char*)&x, sizeof (unsigned int));
- }
- template < typename T > void showType(T x)
- {
- cout << "Type size is: " << sizeof (T) << " ";
- showBytes((unsigned char* )&x, sizeof (T));
- }
- template < typename T > void showTypeWithName(T x,string typeName)
- {
- cout << typeName << " size is: " << sizeof (T) << " ";
- showBytes((unsigned char* )&x, sizeof (T));
- }
- void swapUINT32(unsigned int* ptr)
- {
- unsigned char* p = (unsigned char*) ptr;
- unsigned char t = p[0];
- p[0] = p[3];
- p[3] = t;
- t = p[2];
- p[2] = p[1];
- p[1] = t;
- }
- void swapUINT16(unsigned short int* ptr)
- {
- unsigned char* p = (unsigned char*) ptr;
- unsigned char t = p[0];
- p[0] = p[1];
- p[1] = t;
- }
运行结果示意图:

字节序(endian)
人们在写的时候,一般是高位在前,低位在后。比如数305,419,896 (0x12345678),它的高位是3表示3亿,是高位,6表示6个,是最低位。8表示8百,它的高位在左边,低位在右面。但从我们的输出上看,计算机存储这个数的时候,高低在右边,低位在左边。如下图:

值得注意的是,并不是所有的计算机都是低位节在前,高位字节在后。
高位在前的表示方法俗称“大端”法,反之叫“小端”,字节序这个名称有一个有趣的来源。
“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。
结束语
本节课通过代码,揭示了数据在计算机内部的表示方法,更多内容与计算机原理中会有详细描述。计算机原理也是一门很有趣的课程。本节课中的代码还用到C++函数,模板函数,数组,这些内容我们在后续的课程中还会进一步的讲解。
4297

被折叠的 条评论
为什么被折叠?



