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;

转载于:https://www.cnblogs.com/okwary/articles/1364018.html

Delphi【变体记录及存储方式】相关推荐

  1. record, packed record和变体记录

    //Integer类型刚好是4个字节,ShortInt类型是1个字节,但是Windows中内存是4字节分配, //所以这里其实还是4个字节,用SizeOf可以看到这个record的大小是8字节,这样虽 ...

  2. Delphi 变体类型(Variant)的介绍(流与变体类型的相互转换、变体类型常用的函数)...

    来源:http://blog.csdn.net/xiongmao000738/article/details/6863988 一.变体类型常用的函数介绍: Variant: 一种可以拥有各种数据类型: ...

  3. 学习结构[记录]类型(9) - 变体结构

    变体结构也就是变体记录, 是一个比较复杂的概念. 专家不提倡使用. 兴趣所致, 我想把它弄明白. 一个最大的无符号整数(Cardinal)是 4294967295, 它的大小是 4 字节, 它的二进制 ...

  4. 变体类的使用 package record case【转载】

    **************理论区 start********************* DELPHI中记录的存储方式       在DELPHI中,我们用record关键字来表明一个记录,有时候,我 ...

  5. shader变体是什么_GitHub - 7732050/ShaderVariantCollector

    一种Shader变体收集和打包编译优化的思路 介绍 什么是变体 引用Unity官方文档的解释: ShaderVariant In Unity, many shaders internally have ...

  6. C语言中结构体内存存储方式

    C语言中结构体内存存储方式 结构体的默认存储方式采用以最大字节元素字节数对其方式进行对齐,例如一个结构体中定义有char.int类型元素,则结构体存储空间按照int类型占用字节,如果还有double类 ...

  7. Unity Shader 学习笔记(5)Shader变体、Shader属性定义技巧、自定义材质面板

    写在之前 Shader变体.Shader属性定义技巧.自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用 ...

  8. MATLAB自动驾驶学习(3)——以编程方式创建驾驶场景的变体

    前言 以编程方式创建使用驾驶方案设计器应用生成的驾驶方案的变体,便于基元场景的快速组合生成,能够在多个条件下快速测试驾驶算法,一般在自动化测试时很有用.主流的自动驾驶仿真软件中都支持在程序中直接改变场 ...

  9. 几种前端数据存储方式(记录)

    1. cookie cookie生成cookie是存在客户端,session存在服务器端.在cookie当用户第一次访问网页时,服务器会给客户端返回一个cookie,在cookie中保存着服务器端se ...

最新文章

  1. 华科与浙大计算机学院,计算机最强14所高校排名,清华第2,浙大第4,南大第6,华科第10...
  2. 在AWS中部署OpenShift平台
  3. 白话Elasticsearch41-深入聚合数据分析之案例实战__过滤+聚合:统计价格大于2000的电视平均价格
  4. hibernate教程--常用配置和核心API详解
  5. MFC一一添加WM_USER自定义消息
  6. 微软内部全面拥抱开源流程Inner Source
  7. 手把手教用XNA开发winphone7游戏(三)
  8. 最小拍控制系统详细解读(阶跃输入+速度输入2个案例)【Simulink仿真】
  9. Dynamips使用说明
  10. 【Selenium-WebDriver自学】出现的问题和解决方案(十七)
  11. Eclipse中和编辑相关的快捷键
  12. LINUX下载编译wabt(反编译wasm)
  13. iOS WKWebView 设置默认系统字体
  14. js一键批量打印_前端连接打印机批量打印pdf格式的文件
  15. 室内设计数据手册pdf_室内设计资料集pdf下载-室内设计资料集电子版pdf高清扫描版-东坡下载...
  16. swagger2-2.9.2使用过程中遇到的坑:
  17. discuz论坛的抓取
  18. 第五章人间深情,公母为山
  19. 最新老男孩Linux架构师实战课程14期视频全套1-13天
  20. 创蓝闪验php手机号一键登录

热门文章

  1. 【vjudge contest 418548】2021 BUAA Winter Training 3(Private),签到题ABCDG
  2. 【2020团体程序设计天梯赛】L1部分(PTA,L1-065到L1-072)题解代码
  3. 【CCCC】L2-006 树的遍历 (25分),根据后序与中序遍历建立二叉树(我讨厌树,系列1)
  4. 2019百度之星程序设计大赛 1005 Seq
  5. 第二章 ASP.NET MVC (控制器向视图传递值(二))
  6. JavaScript的Continue关键字和Break关键字
  7. UnityGI2:Lightmaps
  8. python后台架构Django教程——视图views渲染
  9. java获取屏幕截图
  10. jquery系列教程4-事件操作全解