**************理论区 start*********************

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;

**************理论区 end  *********************

 

 

**************演示区 start*********************

type

  TDerivativeAttributeValue = packed record

    case Integer of

      0: (nValue: Integer);

      1: ( wValueLo : SmallInt;

           case Integer of

             0:(wValueHi: SmallInt);

             1:(btValueHiLo : ShortInt;

                btValueHiHi : ShortInt;);

         );

  end;

 

 

// 将int转换成二进制形式

Function Str_IntToBin(Int: LongInt; Size: Integer): String;

Var

  i: Integer;

Begin

  If Size < 1 Then Exit;

  For i := Size Downto 1 Do

    Begin

      If Int And (1 Shl (Size - i)) <> 0 Then

        Result := '1' + Result

      Else

        Result := '0' + Result;

    End;

End;

 

 

procedure TForm1.btn3Click(Sender: TObject);

var

  X: TDerivativeAttributeValue;

 

begin

  {

   1: 给 nvalue赋值  访问其他位 这样的使用 一般作用不大 重点在第二个

  }

  X.nValue := 2147483646;

  ShowMessage(IntToStr(x.nValue) + '->' + Str_IntToBin(x.nValue, 32));

  ShowMessage(IntToStr(x.wValueLo) + '->' + Str_IntToBin(x.wValueLo, 16));

  ShowMessage(IntToStr(x.wValueHi) + '->' + Str_IntToBin(x.wValueHi, 16));

  ShowMessage(IntToStr(x.btValueHiLo) + '->' + Str_IntToBin(x.btValueHiLo, 8));

  ShowMessage(IntToStr(x.btValueHiHi) + '->' + Str_IntToBin(x.btValueHiHi, 8));

 

 

  {

   2: 给 其他的分管符号赋值(各个分管符号有各自的作用)  将nValue数据保存在文件中

  }

  x.wValueLo := 137;

  x.btValueHiLo := 37;

  x.btValueHiHi := 13;

  ShowMessage(IntToStr(x.nValue) + '->' + Str_IntToBin(x.nValue, 32));

end;

 

 

**************演示区 end  *********************

转载于:https://www.cnblogs.com/bbnn38/p/3341835.html

变体类的使用 package record case【转载】相关推荐

  1. 再说变体结构 - 回复 彬 的问题

    问题来源: http://www.cnblogs.com/del/archive/2009/03/01/1032376.html#1464477 假如有这样三种结构, 分别来描述: 直线.圆与三角形: ...

  2. record, packed record和变体记录

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

  3. react 组件样式_如何使用样式化组件为React组件创建视觉变体

    react 组件样式 by Gilad Dayagi 通过吉拉德·达亚吉 如何使用样式化组件为React组件创建视觉变体 (How to create visual variants for Reac ...

  4. Android Studio下项目构建的Gradle配置及打包应用变体

    Gradle简介   Gradle是一个自动化构建工具,采用Groovy的Domain Specific Language(领域特定语言)来描述和控制构建逻辑.具有语法简洁.可读性强.配置灵活等特点. ...

  5. Delphi【变体记录及存储方式】

    DELPHI中记录的存储方式 在DELPHI中,我们用record关键字来表明一个记录,有时候,我们还会看到用packed record来声明的记录,这二者的区别就在于存储方式的不同:在windows ...

  6. axure 8 表格合并_如何在亚马逊创建变体案例 灵活运用拆分/合并变体及基础问题...

    亚马逊如何创建变体流程 多属性商品一般适用于服饰类.珠宝类等商品,我们称之为变体商品.这种商品的形式如下,买家可以选择尺寸和颜色,当卖家选择不同颜色时,商品的图片会随之变化,选择不同尺寸和颜色时,价格 ...

  7. Gradle for Android(五)——构建变体

    当你在开发一个app,通常你会有几个版本.大多数情况是你需要一个开发版本,用来测试app和弄清它的质量,然后还需要一个生产版本.这些版本通常有不同的设置,例如不同的URL地址.更可能的是你可能需要一个 ...

  8. 配置构建变体build.gradle的配置

    google原文链接 https://developer.android.com/studio/build/build-variants.html#product-flavors 配置构建类型 您可以 ...

  9. Gradle for Android-创建build变体

    开发app时,通常都有好几个版本.最常见的就是有一个用来手动测试及保证质量的测试版本和一个生产版本.这些版本通常都有不同的设置.例如,测试版本的API的URL就不同于生成版本的.除此之外,还可能有一个 ...

最新文章

  1. 初试linux编译(ubuntu+vim)+玩转智能蛇
  2. Mybatis常用查找的总结
  3. python输入输出-6、Python 输入输出
  4. pprof 的原理与实现
  5. c#使用System.Windows.Forms.DataVisualization.Charting.dll绘制图表实例
  6. Android应用开发—通用的GridView网格分割线
  7. java 执行oracle 存储过程_oracle--在java中调用存储过程和存储函数
  8. 笨方法学python 习题23
  9. 利用python如何进行数据挖掘
  10. 20个你需要知道的JavaScript简写代码片段
  11. 两列数据对比找不同,并且高亮数据不同的单元格
  12. java版我的世界MITE怎么下_MITE纯新手向教程 - [MITE]MC实在是太简单了 (Minecraft Is Too Easy) - MC百科|最大的Minecraft中文MOD百科...
  13. iVX开发过程整理的常见问题与回答(二)
  14. IDEA中DEBUG时断点变成灰色
  15. Linux keypad 设备树,matrix_keypad 矩阵按键驱动分析
  16. Elasticsearch 的 Shard 和 Segment
  17. appium安装教程和使用中的问题解决
  18. TFN新推出手持式无线电综合测试仪 让测试更方便
  19. 文化产业之作家年财富资料
  20. Security——Okta

热门文章

  1. 使用rancher对Docker容器服务升级
  2. Test Reprot
  3. 2022-2028年中国机制砂石行业投资分析及前景预测报告
  4. 2022-2028年中国麻纺织业投资分析及前景预测报告
  5. 取消打开命令行进入默认anaconda的环境
  6. c/c++ 如何输入带空格的字符串
  7. 预见未来丨机器学习:未来十年研究热点
  8. 编译器设计-解析类型
  9. 图像分类:CVPR2020论文解读
  10. CentOS7:Thrift的安装