当前位置: 首页 > 编程日记 > 正文

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

**************理论区 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

相关文章:

【Boost】系列01:时间与日期

timer库(含timer,progress_timer和progress_display三个组件)和date_time timer用法&#xff1a; #include <boost/timer.hpp> #include <iostream> using namespace std; using namespace boost;int main() {timer t;//开始计时cout<<"max timespan:&q…

git学习网址

1、git 上传代码到GitHub 以及git删除github上文件和文件的命令 - lexsaints - CSDN博客 https://blog.csdn.net/weixin_42350212/article/details/80560272 2、git误区error: failed to push some refs to gitgithub.com: - whaleluo的博客 - CSDN博客 https://blog.csdn.n…

Linux压缩和解压缩命令集

.tar文件 解压tar zxvf FileName.tar打包tar czvf SourceName.tar DirName .gz文件 解压&#xff1a; gunzip FileName.gzgzip -d FileName.gz 压缩 gzip FileName .tar.gz 和.gz文件 解压tar zxvf FileName.tar.gz压缩tar zcvf FileName.tar.gz DirName .bz2文件 解压…

XMPP通讯开发-好友获取界面设计

在XMPP通讯开发-服务器连接 中我们成功连接到服务器上面&#xff0c;然后进入到主界面&#xff0c;接下来就是获取好友列表&#xff0c;这里我们分段开发&#xff0c;首先就是界面的设计&#xff0c;这里仿照QQ好友界面&#xff0c;里面的数据先是用模拟的&#xff0c;下一章获…

linux test数字txt,Linux26期 7月4日预习笔记

9.4/9.5 sed一&#xff0c;打印某行sed命令的格式为&#xff1a;sed -n np filename ,单引号内的n是一个数字&#xff0c;可以使用命令sed -n 1,$p filename ,如下去掉-n是有差异要想把所有行打印出来&#xff0c;可以使用命令sed -n 1,$p filename#sed -n 1,$p 文件名另外&…

提高PHP运行速度的小技巧

使用PHP的最大1个优势就是速度快。一般情况下&#xff0c;PHP总是具有足够的速度支持Web内容动态生成&#xff0c;许多时候甚至无法找出比它更快的方法。然而&#xff0c;当面对庞大的访问量、高负荷的应用、有限的带宽&#xff0c;以及其他各种带来性能瓶颈的因素时&#xff0…

基于Python, Selenium, Phantomjs无头浏览器访问页面

引言&#xff1a; 在自动化测试以及爬虫领域&#xff0c;无头浏览器的应用场景非常广泛&#xff0c;本文将梳理其中的若干概念和思路&#xff0c;并基于代码示例其中的若干使用技巧。 1. 无头浏览器 通常大家在在打开网页的工具就是浏览器&#xff0c;通过界面上输入网址就可以…

groovy–流程控制

在本篇文章中&#xff0c;我们将介绍逻辑分支&#xff0c;循环&#xff0c;以及如何从if-else以及try-catch代码块中返回值。 if – elseGroovy 支持Java传统的if-else语法&#xff1a; def x false def y falseif ( !x ) {x true }assert x trueif ( x ) {x false } else…

c语言中二进制用什么字母表示方法,看C语言编码转换--------负数的二进制表示方法...

今天在看C语言编码转换时&#xff0c;既然对负数的二进制表示有些遗忘&#xff0c;查了下网上的资料&#xff0c;他们说的是个P&#xff01;误人子弟&#xff01;和大家讨论了下&#xff0c;贴出来已备在此遗忘&#xff1a;假设有一个 int类型的数&#xff0c;值为5&#xff0c…

du和df的区别

du,disk usage 是通过搜索文件来计算每个文件的大小然后累加&#xff0c;du能看到的文件只是一些当前存在 的&#xff0c;没有被删除的。他计算的大小就是当前他认为存在的所有文件大小的累加和df,disk free,通过文件系统来快速获取空间大小的信息&#xff0c;当我们删除一个文…

solaris11学习必用工具及ISO

一、软件准备、配置及相关说明1&#xff09;Oracle VM VirtualBox & Oracle VM VirtualBox Extension Pack  http://www.oracle.com/technetwork/server-storage/virtualbox/downloads/index.html#vbox说明&#xff1a;VirtualBox是Oracle自己的东西&#xff0c;很多考试…

谜题59:什么是差?

下面的程序在计算一个int数组中的元素两两之间的差&#xff0c;将这些差置于一个集合中&#xff0c;然后打印该集合的尺寸大小。那么&#xff0c;这个程序将打印出什么呢&#xff1f; import java.util.*;public class Differences {public static void main(String[ ] args) {…

ceph-osd无法获取osd map导致osd down掉的解决办法

环境&#xff1a;ceph-12.2.1 3节点测试性能集群 60块osd 最近ceph集群中有两个osd在重启之后遇到如下问题,osd获取不到集群osdmap产生coredump&#xff1a; ceph version 12.2.1.06 (3e7492b9ada8bdc9a5cd0feafd42fbca27f9c38e) luminous (stable)1: (()0xa2bf21) [0x7fcd9162…

读书笔记2013第13本:《怎样解题》

《怎样解题》这本书是在看《编程大师访谈录》&#xff08;中文版第12页&#xff09;这本书时无意发现的&#xff0c;一个编程大师推荐这本书来指导编程设计&#xff0c;google到这本书后粗略地翻看了一遍&#xff0c;发现是一本教学生如何解数学题的非常有年头的书。随着仔细品…

suse linux登录黑屏,SUSE Linux登录时黑屏解决办法

我采用的virtual pc虚拟机&#xff0c;安装redhat enterprise 4 linux&#xff0c;安装后出现花屏&#xff0c;通过GRUB的单用户模式下修改/etc/X11/xorg.con我采用的virtual pc虚拟机&#xff0c;安装RedHat enterprise 4 linux&#xff0c;安装后出现花屏&#xff0c;通过GRU…

应用构建工具包 Ecere SDK

Ecere SDK是一个跨平台的工具包构建软件应用程序。目前运行在Windows、Linux和Mac OS X(通过X11)。通过 Ecere SDK,可以开发一次应用程序,并将其部署在所有支持的平台上与一个轻量级运行时环境。它引入了eC这个面向对象语言来源于和完全兼容C,性能好也易于使用。一个内置的3d引…

第39-43课 thinkphp5完成商品会员价格功能(后置勾子afterInsert)

目录 功能一:利用后置勾子,处理好商品主键id,会员的价格,再插入member_price表里.要实现的功能:思路:html里控制器里模型里的后置勾子afterInsert()功能二:利用后置勾子,上传图片,批量生成缩略图,再插入goods_photo表里.要实现的功能:控制器里的用调用模型用save()方法保存模型…

codeforces A. Jeff and Digits 解题报告

题目链接&#xff1a;http://codeforces.com/problemset/problem/352/A 题目意思&#xff1a;给定一个只有0或5组成的序列&#xff0c;你要重新编排这个序列&#xff08;当然你可以不取尽这些数字&#xff09;&#xff0c;使得这个序列尽可能地大&#xff0c;并且能被90除尽。 …

内核方式挂载cephfs

我们内核挂载的前提是&#xff1a;看到centos7.5 中默认内核3.10.0-862.11.6.el7.x86_64的挂载fs执行文件读写性能更优良&#xff0c;所以尝试将3.10.0-862.11.6.el7.x86_64模块中与ceph fs挂载相关的ceph.ko,libceph.ko,dns_resolver.ko,libcrc32c.ko拷贝到自己的设备。 同样要…

汉诺塔怎么加计数次数c语言,C语言计算汉诺塔最小移动步数 (二)

前几天写的&#xff1a;C语言计算汉诺塔最小移动步数(一)当时还不知道用2^n-1这个公式来求解汉诺塔移动步骤。_偶然间在网上发现了这个公式&#xff0c;发现当时写的算法还是比较繁琐的。所以又根据这个公式又写了一个。那篇的实现是两个数组来回赋值&#xff0c;这个是用一个数…

Myeclipse 8.0 +Flash builder 4 plugin 的实现

其实过程非常&#xff0c;简单&#xff0c;但是我之前在网上找了很多资料都说&#xff0c;需要先装 Eclipse 3.5 &#xff0c;然后安装MyEclipse 8.0的插件到Eclipse&#xff0c;最后再安装Flash builder 的插件&#xff0c;期间还要进行一些文件的复制和转移等&#xff0c;弄得…

DHCP服务搭建

DHCP服务 一、DHCP概述 DHCP&#xff08;Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议&#xff09;通常被应用在大型的局域网络环境中&#xff0c;主要作用是集中的管理、分配IP地址&#xff0c;使网络环境中的主机动态的获得IP地址、Gateway地址、DNS服务…

根据c语言数组定义填写下表,C语言程序设计 自测题(三)

{ n;if(n%3!0) continue;k--; }printf("%d,%d/n",k,n);}程序运行后的输出结果是______。A、1,1B、2,2C、3,3D、4,435、以下不能正确定义二维数组的选项是______。A、int a[2][2]{{1},{2}};B、int a[][2]{1,2,3,4};C、int a[2][2]{{1},2,3}D、int a[2][]{{1,2},{3,4}…

linux if 命令判断条件总结

linux if命令 关于文件属性的判断式 -a 如果文件存在 -b 如果文件存在&#xff0c;且该文件是区域设备文件 -c 当file存在并且是字符设备文件时返回真 -d 当pathname存在并且是一个目录时返回真 -e 当pathname指定的文件或目录存在时返回真 -f 当file存在并且是普通文件时返回真…

ppt文本框显示缺字,信息显示不全

1.在文字后面加个空格。2.重新调整文本框大小3.不需要打开ppt&#xff0c;而是在图标上右键属性-摘要&#xff0c;把标题、主题、作者等描述全部清空或改成与本机用户一至即可。因为文本框少子是信息不匹配&#xff0c;就像歌曲在mp3里播放出现的乱码一样。具体能否解决问题&am…

property装饰器

# 需要了解的property的用法 class People:def __init__(self,name):self.__namenamepropertydef name(self):return <name:%s> %self.__namename.setterdef name(self,new_name):if type(new_name) is not str:print(名字必须是str类型)returnself.__namenew_namename.d…

f-fdisk做磁盘分区,起始扇区从2048块开始

文章目录First Sector 起始扇区fdisk工具加分区fdisk删除分区First Sector 起始扇区 默认从第2048块扇区开始是因为,由于EFI的兴起&#xff0c;要给EFI 代码留磁盘最开始的1M空间&#xff0c;即2048*521/(1024*1024)1M With the death of the legacy BIOS (ok, its not quite …

c语言 静态链表插入排序,数据结构C语言版 表插入排序

西门豹治邺奇计数据结构C语言版 表插入排序.txt两个人吵架&#xff0c;先说对不起的人&#xff0c;并不是认输了&#xff0c;并不是原谅了。他只是比对方更珍惜这份感情。/*数据结构C语言版 表插入排序算法10.3 P267-P270编译环境&#xff1a;Dev-C 4.9.9.2日期&#xff1a;201…

C/C++流程图生成器 C转流程图【worldsing笔记】

此版本仅供学习&#xff0c;请大家支持正版软件&#xff01;&#xff01; AutoFlowChart v3.1软件下载&#xff1a; http://url.cn/OUK17C 支持导出&#xff1a;word、visio、图片格式。 例如&#xff1a;main.c #include "stdio.h" void main () {int s ; void f(in…

iOS编码:如何创建gbk编码

原文摘自&#xff1a;http://www.cnblogs.com/kiao295338444/articles/2590031.html 我们知道&#xff0c;使用NSURLConnection的代理方法下载网页&#xff0c;存到一个NSData中&#xff0c; NSMutableData *pageData; [pageData appendData:data]; 如果网页编码是UTF-8的&…