转载:http://www.cnblogs.com/huangjacky/archive/2009/12/08/1619315.html
技术交流,DH解说.
哈哈,学一下xiaoy.
今天这里我想说一下,Delphi里面的数据,当然不是数据类型,如果有朋友想看数据类型的直接打开Delphi的帮助就可以了.我们主要来看下数据在内存中的分布,以及我们怎么使用,其实这就不局限于Delphi了.
任何数据在内存中都是一堆二进制,各种数据结构都是对这些二进制进行堆积木而已.比如说Byte,Char,Boolean只是使用一个字节的数据,而Word,ShortInt就使用2个连续字节的数据,以此类推吧.
基本数据是这样了,那么复杂一点儿数据呢?
首先看数组:
7 |
ShowMessage(IntToStr(A[I])); |
我们可以看到代码运行后A中数据是0,3,6,9,12,15,18,21.
我们跑到Delphi里面去看一下:
当然这里是16进制,自己转一下了.
我们结论了,数组中元素在内存中式紧挨着的.
不信?改成Integer看下
2 |
A: array [ 0..7 ] of Integer ; |
7 |
ShowMessage(IntToStr(A[I])); |
注意:多字节的,如Integer在内存中都是小头的.也就是假如一个整数Integer是$01234567那么他在内存中应该是67 45 23 01的.嘿嘿,上面我们能看到这个8个Integer都是紧凑在一起的.
接着讲讲结构体.
我们必须要了解到什么叫做数位对齐,在C++里面也有这个概念.
在我们32位操作系统中,数据处理都是4个字节4个字节来的,以前有人在问计算机访问什么数据最快,一群人在这里说字节.瀑布汗.
有了这个概念我们可以知道,结构体每个域都想凑成4的整数倍.
看个例子:
18 |
ShowMessageFmt( '%D,%D' ,[SizeOf(A),SizeOf(B)]); |
这里我们看到A的大小是8,B的大小是5.看下内存中的情况:
A的情况: 0D后面填充了3个00
B的情况: 0D和FF紧挨着的.
packed主要是为了节约空间但是牺牲了效率.
结论:结构体中的数据也是紧挨着的.
我这里不讲字符串了,以为原来博客有个文章讲了的.晚上回去转过来.
说了这么多有什么用?这个是大家最关心的.
1 数据类型的转换.
前几天看见GraphicEx里面一个东西:
TChunk = array[0..3] of Char;
然后他要把这个转换成一个Cardinal大家说怎么办?
肯定多数人想到的第一个方法是:
02 |
TChunk = Array [ 0..3 ] Of Char ; |
04 |
Function Change( A: TChunk ): Cardinal ; |
06 |
Result := ( ord( A[ 3 ] ) Shl 24 ) Or |
07 |
( ord( A[ 2 ] ) Shl 16 ) Or |
08 |
( ord( A[ 1 ] ) Shl 8 ) Or |
的确这样做没错.但是我们知道这个数组4个字节在内存的排序和Cardinal在内存中的排序是一样的,那么我们只要把它强制转换一下,当然这里不是用强制类型转换,是指针.
1 |
Function Change1( A: TChunk ): Cardinal ; |
3 |
Result := PCardinal( @A[ 0 ] )^ |
是不是简单多了?为什么可以这样?
我们来分析下:
A在内存中肯定是这样的: A[0] A[1] A[2] A[3]
一个Cardinal $01234567在内存中是: 67 45 23 01
那么我们只要让一个Cardinal从A[0]开始就行了,所以我们看到直接将一个PCardinal指针=A[0]的地址就行了.
OK,同志们觉得有更简单的方法没有?上面的代码是不是已经很精简了?
难道一句代码都不用就可以转换?
答案是可以的.
1 |
Function Change2( A: TChunk ): Cardinal ; |
这样就可以了.
这里需要一点儿汇编知识,我先不讲了.原理一样的就是同一地址不同指针而已.
2 成块操作
当我们有两个结构数组,我们想Copy其中一个到另一个去,怎么办?
你又想用For循环?何苦何必呢?
1 |
procedure MyCopy(Count: Integer ; var Dst; const src); |
3 |
Move(src,dst,Count * SizeOf(TA)); |
我们只需要调用
MyCopy(5,A[1],B[0]);
那么B[0]..B[4]的内容都到A[1]..A[5]里面去了.(A和B都是TA的数组)
为什么?
因为结构体内容在内存是连续的,所以我们只要指定好起始位置和长度,然后把这块内存copy到另一个地方去,不就实现了复制了么?
能力有限,今天就讲到这里,我是DH.
(LiveWriter写的不知道代码有没有高亮,用了插件的)