zoukankan      html  css  js  c++  java
  • 学习结构[记录]类型(9) 变体结构

    变体结构也就是变体记录, 是一个比较复杂的概念. 专家不提倡使用.
    兴趣所致, 我想把它弄明白.

    一个最大的无符号整数(Cardinal)是 4294967295, 它的大小是 4 字节, 它的二进制表示是:
    11111111 11111111 11111111 11111111

    它的低字节的值是 11111111, 也就是十进制的 255

    //测试: var c: Cardinal; begin c := 4294967295; ShowMessage(IntToStr(Lo(c))); {会显示: 255; Lo 是获取低字节值的函数} end;
    一个 Byte 类型的最大值是 255, 它的大小是 1 个字节, 用二进制表示是:
    11111111

    假如把一个 Cardinal 类型的值赋给一个 Byte 类型的值, Byte 将只取 Cardinal 的最低字节.

    //测试: var c: Cardinal; b: Byte; begin c := 4294967295; b := c; ShowMessage(IntToStr(b)); {255} c := 258; {二进制表示: 00000000 00000000 00000001 00000010} b := c; {b 将只获取: 00000010} ShowMessage(IntToStr(b)); {2} end;
    这是我们能否会想到, 在结构会储存时, 一个可以储存 Cardinal 的空间, 当然也能得放下一个 Byte 值;
    如果这个值非此即彼, 我们完全不需要两个储存空间.
    我猜测, 这应该是 Delphi 设计变体记录的初衷.
    //假如有这样一个员工登记表
    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;
    本话题暂时到这吧. 另参见: 再说变体结构

  • 相关阅读:
    ADC测试matlab代码
    matlab的滤波器仿真——低通滤波器与插值滤波器
    PDF转Image最终方案
    多线程和蕃茄炒蛋
    git学习总结
    踩坑了,当前目录问题
    Angular 1.x 升级到 Angular 2
    打造AngularJs2.0开发环境
    发布一个自用的ansi转utf8程序
    用itextsharp打印pdf示例
  • 原文地址:https://www.cnblogs.com/del/p/1032376.html
Copyright © 2011-2022 走看看