`
美丽的小岛
  • 浏览: 310601 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

DELPHI中记录的存储方式[转]

 
阅读更多

在DELPHI中,我们用record关键字来表明一个记录,有时候,我们还会看到用packed record来声明的记录,这二者的区别就在于存储方式的不同;在windows中,内存的分配一次是4个字节的,而Packed按字节进行内存的申请和分配,这样速度要慢一些,因为需要额外的时间来进行指针的定位。因此如果不用Packed的话,Delphi将按一次4个字节的方式申请内存,因此如果一个变量没有4个字节宽的话也要占4个字节!这样浪费了一些空间,但提高了效率。

例如一个记录,以,sizeof(okwary)应该得到8。而如果使用packed关键字,那么sizeof(okwary)则得到5。

   type okwary= record
     age : integer;
     sex : shortint;    
   end;

      其中age是integer类型,正好4个字节,而sex是showint类型,占用一个字节,但基于4字节得内存分配方式,这里它也将占用4个字节。


DELPHI中的变体记录

在DELPHI中,观察Tmessage和TTypeData的定义,从关键字record,你一眼就可以看出,它是一个记录类型,但仔细观察,你又会发现在它的定义中出现了case关键字。它代表什么呢?

它代表此记录是变体记录。让我们先去了解一下变体记录。

一个典型的变体记录定义如下:

type  recordTypeName  =  record  
   fieldList1:  type1;  
   ...  
   fieldListn:  typen;  
case  tag:  ordinalType  of  
   constantList1:  (variant1);  
   ...  
   constantListn:  (variantn);  
end

其中case到结尾部分定义了多个变体字段。所有变体字段共享一段内存大小又最大变体字段决定。

使用变体记录时要注意: 

(1)Long  String、WideString、Dynamic  Array、Interface的大小都是指针大小,  OleVariant其实就是COM  SDK中的VARIANT结构,大小是16字节。

但在Object  Pascal中它们都需要自动终结化,如果它们出现在variant  part中,编译器就无法知道它们是否应该进行终结化――因为不知道当前存储的是哪种类型。   

(2)所有变体字段共享一段内存。而共享内存的大小则由最大变体字段决定。 

(3)当tag存在时,它也是记录的一个字段。也可以没有tag。 

(4)记录的变体部分的条件域必须是有序类型

(5)记录类型中可以含有变体部分,有点象case语句,但没有最后的end,变体部分必需在记录中其他字段的声明之后

 

事实上Delphi中内存的几乎所有的变体记录都有一个特点(尽管这不是要求的),就是所有变体部份长度部和都是一样的,比如:

   TMessage = packed record
     Msg: Cardinal;
     case Integer of
       0: (
         WParam: Longint;
         LParam: Longint;
         Result: Longint);
       1: (
         WParamLo: Word;
         WParamHi: Word;
         LParamLo: Word;
         LParamHi: Word;
         ResultLo: Word;
         ResultHi: Word);
   end;

WParam,LParam,Result三个字段的长度和是12个字节,而WParamLo,WParamHi,LParamLo,LParamHi,ResultLo,ResultHi六个字段之和也是12个字符,同时仔细观察,会发现后面六个字段中的每两个字段与前面三个字段中的每一个字段都是对应的.

再看看
   TRect = packed record
     case Integer of
       0: (Left, Top, Right, Bottom: Longint);
       1: (TopLeft, BottomRight: TPoint);
   end;
是不是也是一样的呢?

 

变体记录得作用

(1)节约空间。对于那些要根据条件而决定是否存储得类型,完全可以利用变体记录来达到节约空间得效果。例如,一个公司的员工薪水可以是月薪、年薪等方式,那么并没有必要在记录中都分配空间而又用不到。

(2)类型的转换。例如,如果有一个64位的整数类型作为变体的第一个字段,一个32位的整数Integer类型作为另一个变体的第一个字段,那么可以向64字段赋值然后以整数Integer字段读出其前32位

 

 

//假如有这样一个员工登记表
type TpersonRec = record
    ID: Integer;            {员工编号}
    case Boolean of         {根据分类}
      True:  (A: Cardinal); {如果是股东, 登记年薪}
      False: (B: Word);     {如果不是,   登记日薪}
  end;
var
  personRec: TpersonRec;
begin
  {先算一算这个结构的大小:
    ID 是 Integer  类型, 应该是   4  字节大小;
    A  是 Cardinal 类型, 也应该是 4  字节大小;
    B  是 Word     类型, 应该是   2  字节大小;
    合计为                        10 个字节.
  }

  {可事实, TpersonRec 只有 8 个字节}
  ShowMessage(IntToStr(SizeOf(TpersonRec))); {8}

  {
    原因是: 字段 A 和 字段 B 公用了一个储存空间;
    当然这个储存空间得依着大的, 是 Cardinal 的尺寸 4 个字节.
  }


//赋值测试:
  personRec.ID := 110;
  personRec.A  := 100000{一看就知道是个股东}

//取值:
  ShowMessage(IntToStr(personRec.A)); {100000; 这不可能有错, 十万大洋}

//但是:
  ShowMessage(IntToStr(personRec.B)); {34464 ?! 难道这是工人的日薪吗?}
  {
    首先, A 和 B 两个字段占用同一个空间, 给其中一个赋值, 另一个当然也就有值了;
    但因为数据类型的容量不同, 它们的值有可能是不一样的.
    在很多情况下, 我们可能根本不去理会另一个值, 但如果的确需要呢?
    看下一个例子:
  }

end;



type
  TpersonRec = record
    ID: Integer;
    case tag: Boolean of    {在这里加了一个 tag 变量}
      True:  (A: Cardinal);
      False: (B: Word);
  end;
var
  personRec: TpersonRec;
begin
  {我们可以用 tag 变量来区分, 记录中变体部分的值到底是谁的, 譬如:}
  personRec.ID  := 110;
  personRec.tag := True;
  personRec.A   := 100000{股东的的年薪}

  personRec.ID  := 111;
  personRec.tag := False;
  personRec.B   := 100;    {工人的日薪}
end;



//最经典的变体结构莫过于 Delphi 定义的 TMessage 结构了, 两组数据分分合合都是一体, 多么巧妙啊!

TMessage = packed record
    Msg: Cardinal;
    case Integer of
      0: (
        WParam: Longint;
        LParam: Longint;
        Result: Longint);
      1: (
        WParamLo: Word;
        WParamHi: Word;
        LParamLo: Word;
        LParamHi: Word;
        ResultLo: Word;
        ResultHi: Word);
  end;

分享到:
评论

相关推荐

    DELPHI中的记录类型【存储方式和变体记录】.mht

    DELPHI中的记录类型【存储方式和变体记录】.mht

    Delphi中记录文件的操作示范及详细介绍

    在Delphi编程环境中,记录文件是一种非常重要的数据存储方式,尤其适用于需要高效读写固定结构数据的应用场景。本文将深入介绍Delphi中的记录文件操作方法,并通过示例代码来展示如何进行记录文件的基本操作。 ####...

    delphi 中英文 键盘记录源码

    在压缩包内的 "键盘记录DALL" 文件,很可能是这个键盘记录功能的DLL文件,用户可能需要将这个DLL导入到Delphi项目中,或者通过其他方式在运行时加载,以便利用它的功能。为了调试和修复BUG,开发者需要反编译或使用...

    Delphi实现繁体中文与简体中文互转

    在Delphi中,可以通过DLL封装的方式来使用OpenCC,将C++编译的动态链接库(DLL)导入到Delphi项目中,并定义相应的接口来调用其转换函数。 以下是一个简化的Delphi代码示例,展示了如何封装OpenCC的DLL并调用转换...

    Delphi中调用oracle的存储过程返回数据集

    在 Delphi 中调用 Oracle 的存储过程返回数据集有两种方式,一种是使用 Oracle 提供的 OLE DB 提供程序,另一种是使用 Oracle 的 OCI(Oracle Call Interface)提供程序。这里我们主要介绍使用 OLE DB 提供程序的...

    Delphi FireDac Delta 记录操作日志 与 Delta转SQL

    - 使用 FDMemTable:FDMemTable 是 FireDAC 提供的一种内存中的数据表,你可以将它用作临时存储,用来记录用户对数据的操作。当你对 FDMemTable 进行插入、更新或删除操作时,Delta 会自动跟踪这些变化。 - 开启 ...

    DELPHI如何记录屏幕操作

    以上就是使用Delphi记录屏幕操作的基本步骤和技术要点,通过这些技术,开发者可以构建出功能强大的屏幕操作记录和回放软件。在实际应用中,还可以结合其他技术,如添加语音注释、时间线编辑等,以增强软件的实用性和...

    delphi读写取流记录文件TFileStream

    在本篇文章中,我们将深入探讨如何使用TFileStream来读写流记录文件,以及如何实现img格式图片的追加存储。 首先,让我们了解TFileStream的基本用法。在Delphi中,你可以通过以下步骤创建一个TFileStream对象: 1....

    Delphi 鼠标键盘记录回放源程序

    《Delphi鼠键记录回放源程序解析与应用》 Delphi是一款强大的Windows应用程序开发工具,以其直观的可视化界面和高效的编程模型深受开发者喜爱。在IT领域,有时我们需要记录并回放用户的鼠标和键盘操作,这在自动化...

    Delphi文本和数据库表格记录的转换..rar

    "Delphi文本和数据库表格记录的转换"这一主题涉及的是如何在Delphi应用程序中处理文本数据和数据库之间的转换。在实际开发中,这种转换经常发生,例如从CSV文件导入数据到数据库,或者将数据库中的记录导出为文本...

    Delphi bmp图片转RGB byte方法

    ### Delphi BMP 图片转 RGB Byte 方法解析 #### 核心知识点概述 本文将深入探讨一个在 Delphi 开发环境中使用的函数,该函数用于将 BMP 图像格式转换为 RGB Byte 数组。通过此函数,我们可以方便地处理图像数据,...

    mouseRecordet delphi 记录播放 鼠标键盘动作 原程序

    1. Windows API:Delphi可以通过调用Windows API函数,如GetAsyncKeyState、GetCursorPos等,实时获取键盘状态和鼠标位置,将这些信息存储到数据结构中,实现鼠标键盘动作的记录。 2. 自定义数据结构:为了存储鼠标...

    Delphi文本和数据库表格记录的转换

    数据库表格则更结构化,如在SQL数据库中,数据存储在表中,每个表有明确的字段定义和关系。 在Delphi中,我们可以使用多种方法来实现文本和数据库表格的转换。以下是一些关键步骤和工具: 1. **读取文本文件**:...

    Delphi 鼠标键盘记录回放

    综上所述,"Delphi 鼠标键盘记录回放"项目涵盖了事件处理、数据存储与序列化、API调用、文件操作等多个方面,对Delphi开发者来说,这是一个练习系统编程和用户交互的有益实践。通过实现这个项目,开发者不仅可以提升...

    Delphi XML转HTML

    在Delphi中,可以使用TXMLDocument和TXSLTransform组件来执行这个转换过程。首先,将XML文档加载到TXMLDocument组件,然后加载XSLT转换模板到TXSLTransform组件。最后,调用TXSLTransform的TransformNode或...

    delphi查询域名MX记录

    在IT行业中,网络通信是至关重要的部分,而电子邮件服务作为其中一种基础通信方式,依赖于MX(Mail Exchange)记录来确保邮件的正确投递。MX记录是DNS(Domain Name System)的一部分,它定义了一个域的邮件服务器,...

    基于delphi的键盘记录器

    **基于Delphi的键盘记录器** 在编程领域,Delphi是一种强大的对象 Pascal 编程环境,常用于开发桌面应用程序。这个“基于Delphi的键盘记录器”是一个利用Delphi编程语言构建的小型实用程序,其核心功能是捕获并记录...

    delphi制作的简单的日常记录程序

    在本项目"delphi制作的简单的日常记录程序"中,开发者运用了Delphi的强大功能,创建了一个实用的日常记录工具,旨在帮助用户方便地管理他们的日常事务。 这个程序实现了以下主要功能: 1. **添加记录**:用户可以...

    delphi中调用oracle的存储过程.doc

    在 Delphi 中调用 Oracle 存储过程是数据库应用程序开发中的常见操作,特别是在报表解决方案中。Oracle 存储过程能够封装复杂的 SQL 语句和业务逻辑,提高代码的可维护性和执行效率。以下是如何在 Delphi 中使用 ...

    Delphi中的ADOquery 用法

    在 Delphi 中,ADOquery 可以通过 sql 的存储过程来实现数据的添加、修改和删除操作。下面是通过 sql 的存储过程来实现的示例代码: 添加: With ADOQuery1 do begin Close; SQL.Clear; SQL.Add(' Insert Into ...

Global site tag (gtag.js) - Google Analytics