Delphi - 数据的理解

本文深入探讨Delphi中数据在内存中的分布与使用技巧,包括数组、结构体的操作及数据类型的转换方法,旨在提高编程效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


======================================================
注:本文源代码点此下载
======================================================

技术交流,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.看下内存中的情况:

a的情况: 0d后面填充了3个00

b的情况: 0d和ff紧挨着的.

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^)/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值