跟我学“数据结构”系列:用程序探索数据
摘要:
关键字
引言
在开始数据结构之前,我们先来一节基础课:“数据”
最近数十年来,计算机领域高速发展,计算机已深入到各行各业,已能处理像如文字、图形、图像、声音等代表不同属性的信息。本文从程序员观点,利用
c++
程序来探索计算机是如何表示和处理数据的。
适用的读者
:
初级
相关性:
本文是学习后续“数据结构”课程的基础。
二进制
电脑内部为什么要用二进制呢?这是因为二进制中只有两个数,即
0
和
1
。二进制数在电气元件中容易实现、容易运算,在电子学中具有两种稳定状态以代表
0
和
1
。而需要由
0
和
1
来代表的量很多。如:电压的高和低,电灯的亮和灭,电容的充电和放电,脉冲的有和无,晶体管的导通和截止等。总之,电脑内部使用二进制,主要是为了设计和制造电脑方便。
先假定普通灯泡只有亮、灭两种状态。以灯泡为工具,我们来探析计算机中数据是如何表示的:
我们把一个灯泡称为一“位”,当有一“位”灯泡(用格子表示)的时候,能表示两个数,这两个数
0
和
1
。
[p1.jpg]
![](http://student.csdn.net/attachment/200905/28/41561_1243538270ZE99.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
个“位”合在一起,称为一个字节。字节是计算机处理信息的最小单位。
、
![](http://student.csdn.net/attachment/200905/28/41561_1243539587TjJk.jpg)
信息表示形式
日常人们通常用十进制来表示一个数。如
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;
- }
运行结果示意图:
![](http://student.csdn.net/attachment/200905/28/41561_1243539568bza3.jpg)
字节序(endian)
人们在写的时候,一般是高位在前,低位在后。比如数
305,419,896 (0x12345678)
,它的高位是
3
表示
3
亿,是高位,
6
表示
6
个,是最低位。
8
表示
8
百,它的高位在左边,低位在右面。但从我们的输出上看,计算机存储这个数的时候,高低在右边,低位在左边。如下图:
![](http://student.csdn.net/attachment/200905/28/41561_1243538028XF66.jpg)
值得注意的是,并不是所有的计算机都是低位节在前,高位字节在后。
高位在前的表示方法俗称“大端”法,反之叫“小端”,字节序这个名称有一个有趣的来源。
“endian”
这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头
(Big-Endian)
敲开还是从小头
(Little-Endian)
敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。
结束语
本节课通过代码,揭示了数据在计算机内部的表示方法,更多内容与计算机原理中会有详细描述。计算机原理也是一门很有趣的课程。本节课中的代码还用到C++函数,模板函数,数组,这些内容我们在后续的课程中还会进一步的讲解。