======================================================
注:本文源代码点此下载
======================================================
技术交流,dh解说.
哈哈,学一下xiaoy.
今天这里我想说一下,delphi里面的数据,当然不是数据类型,如果有朋友想看数据类型的直接打开delphi的帮助就可以了.我们主要来看下数据在内存中的分布,以及我们怎么使用,其实这就不局限于delphi了.
任何数据在内存中都是一堆二进制,各种数据结构都是对这些二进制进行堆积木而已.比如说byte,char,boolean只是使用一个字节的数据,而word,shortint就使用2个连续字节的数据,以此类推吧.
基本数据是这样了,那么复杂一点儿数据呢?
首先看数组:
var
a:array[0..7] of byte;
i:integer;
begin
for i:=0 to 7 do
a[i]:=i * 3;
showmessage(inttostr(a[i]));
end;
我们可以看到代码运行后a中数据是0,3,6,9,12,15,18,21.
我们跑到delphi里面去看一下:
当然这里是16进制,自己转一下了.
我们结论了,数组中元素在内存中式紧挨着的.
不信?改成integer看下
var
a:array[0..7] of integer;
i:integer;
begin
for i:=0 to 7 do
a[i]:=i * 3;
showmessage(inttostr(a[i]));
end;
注意:多字节的,如integer在内存中都是小头的.也就是假如一个整数integer是$01234567那么他在内存中应该是67 45 23 01的.嘿嘿,上面我们能看到这个8个integer都是紧凑在一起的.
接着讲讲结构体.
我们必须要了解到什么叫做数位对齐,在c++里面也有这个概念.
在我们32位操作系统中,数据处理都是4个字节4个字节来的,以前有人在问计算机访问什么数据最快,一群人在这里说字节.瀑布汗.
有了这个概念我们可以知道,结构体每个域都想凑成4的整数倍.
看个例子:
type
ta = record
c:byte;
d:integer;
end;
tb = packed record
c:byte;
d:integer;
end;
var
a:ta;
b:tb;
begin
a.c:=13;
a.d:=255;
b.c:=13;
b.d:=255;
showmessagefmt('%d,%d',[sizeof(a),sizeof(b)]);
end;
这里我们看到a的大小是8,b的大小是5.看下内存中的情况:
packed主要是为了节约空间但是牺牲了效率.
结论:结构体中的数据也是紧挨着的.
我这里不讲字符串了,以为原来博客有个文章讲了的.晚上回去转过来.
说了这么多有什么用?这个是大家最关心的.
1 数据类型的转换.
前几天看见graphicex里面一个东西:
tchunk = array[0..3] of char;
然后他要把这个转换成一个cardinal大家说怎么办?
肯定多数人想到的第一个方法是:
type
tchunk = array[ 0..3 ] of char ;
function change( a: tchunk ): cardinal ;
begin
result := ( ord( a[ 3 ] ) shl 24 ) or
( ord( a[ 2 ] ) shl 16 ) or
( ord( a[ 1 ] ) shl 8 ) or
ord( a[ 0 ] )
end ;
的确这样做没错.但是我们知道这个数组4个字节在内存的排序和cardinal在内存中的排序是一样的,那么我们只要把它强制转换一下,当然这里不是用强制类型转换,是指针.
function change1( a: tchunk ): cardinal ;
begin
result := pcardinal( @a[ 0 ] )^
end ;
是不是简单多了?为什么可以这样?
我们来分析下:
a在内存中肯定是这样的: a[0] a[1] a[2] a[3]
一个cardinal $01234567在内存中是: 67 45 23 01
那么我们只要让一个cardinal从a[0]开始就行了,所以我们看到直接将一个pcardinal指针=a[0]的地址就行了.
ok,同志们觉得有更简单的方法没有?上面的代码是不是已经很精简了?
难道一句代码都不用就可以转换?
答案是可以的.
function change2( a: tchunk ): cardinal ;
asm
end ;
这样就可以了.
这里需要一点儿汇编知识,我先不讲了.原理一样的就是同一地址不同指针而已.
2 成块操作
当我们有两个结构数组,我们想copy其中一个到另一个去,怎么办?
你又想用for循环?何苦何必呢?
procedure mycopy(count:integer;var dst;const src);
begin
move(src,dst,count * sizeof(ta));
end;
我们只需要调用
mycopy(5,a[1],b[0]);
那么b[0]..b[4]的内容都到a[1]..a[5]里面去了.(a和b都是ta的数组)
为什么?
因为结构体内容在内存是连续的,所以我们只要指定好起始位置和长度,然后把这块内存copy到另一个地方去,不就实现了复制了么?
能力有限,今天就讲到这里,我是dh.
(livewriter写的不知道代码有没有高亮,用了插件的)
======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/