• 谈谈 Delphi 的类型与指针[2]


    内存中的数据除了 0 便是 1, 你把它当作图片、字符、数字等等, 那是你的事, 内存只认识 0 和 1.

    Win32 系统除了使用硬内存以外, 还可以从硬盘上开辟虚拟内存;

    因为 Win32 的内存地址范围在 4 个 G 以内(0..232-1), 所以它最多能够给一个应用程序分配 4G 的运行空间; 并且其中的 2G 有系统管理, 实际上程序只有 2G 的自主空间. 还记得有说 String 最大长度是 2G 吗? 就是这个道理.

    有 4G 的内存, 就有 4G 个地址, 也就是最多可以有 (1024*1024*1024*4 - 1 = 4294967295) 个内存地址, 这刚好是 Delphi 中 Cardinal 的最大值, 所以 32 位的指针类型追到底都是 Cardinal 类型的一个数字.

    一个内存地址是 0..4294967295 之间的一个数字, 你可以通过内存地址读取或写入数据;
    一个指针要用来索引或标识内存, 它也是 0..4294967295 之间的一个数字; 它们虽不相同, 但通过指针可以找到实际存储数据的内存地址, 并按指定的类型去读写它.

    譬如:
    var
      str: string;
      n: Cardinal;
      pstr: PString;
    begin
      str := 'ABCDE';
      n := Cardinal(str); {获取内存地址}
      pstr := @str;       {现在 pstr 是 str 的指针}
    
      {n 与 pstr 的数字结果是(结果是随机的, 知道不一样就行了):}
      ShowMessage(IntToStr(n));              {4571092}
      ShowMessage(IntToStr(Cardinal(pstr))); {1244652}
    
      {但通过 pstr 可以找到 str}
      ShowMessage(pstr^); {ABCDE}
    end;
    
    程序运行后, 字符串所在的内存基本上是下面这个样子(以字节为单位), 上例中的 n 标识着 ↓ 的位置:
    A B C D E

    换二进制图示一下:
    00001010 00001011 00001100 00001101 00001110

    如果只看二进制, 这个数据到底是什么很难知道; 再说它为什么非得是字符串 "ABCDE" 呢? 这可不一定.

    下面的例子中, 我们先是权且把它当作字符串, 但随着指针的移动, 字符串也在变化.

    然后, 有分别把它分别用 Byte 指针(PByte) 和 Integer 指针(PInteger) 去读取它, 也会得到相应的值.

    完整示例如下:
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        Button3: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button3Click(Sender: TObject);
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      str: string;
      ps: PChar;
      n: Cardinal;
    begin
      str := 'ABCDE';
      ps := PChar(str);
      n := Cardinal(ps);
      //n := Cardinal(str); {这行可以代替上面两行}
      ShowMessage(IntToStr(n)); {结果是 Windows 随机管理的}
    
      ShowMessage(PChar(n));   {ABCDE}
      ShowMessage(PChar(n+1)); {BCDE}
      ShowMessage(PChar(n+2)); {CDE}
      ShowMessage(PChar(n+3)); {DE}
      ShowMessage(PChar(n+4)); {E}
    end;
    
    procedure TForm1.Button2Click(Sender: TObject);
    var
      str: string;
      n: Cardinal;
      pb: PByte;
    begin
      str := 'ABCDE';
      n := Cardinal(str);
      ShowMessage(IntToStr(n)); {4571140; 这是我这里的结果, 这是随机的}
    
      pb := PByte(n);
      ShowMessage(IntToStr(pb^)); {65}
      pb := PByte(n+1);
      ShowMessage(IntToStr(pb^)); {66}
    end;
    
    procedure TForm1.Button3Click(Sender: TObject);
    var
      str: string;
      n: Cardinal;
      pint: PInteger;
    begin
      str := 'ABCDE';
      n := Cardinal(str);
      ShowMessage(IntToStr(n)); {4571140; 这是我这里的结果, 这是随机的}
    
      pint := PInteger(n);
      ShowMessage(IntToStr(pint^)); {1145258561}
      pint := PInteger(n+1);
      ShowMessage(IntToStr(pint^)); {1162101570}
    end;
    
    end.
    
    上面的第三个程序段的结果或许让你迷惑:
    第一个结果, 应该和 "ABCD" 有点关系才对啊, 怎么是: 1145258561 ?
    第二个结果, 应该和 "BCDE" 有点关系才对啊, 怎么是: 1162101570 ?

    为什么呢? 这当然没错, 听我解释:
    1145258561 转换成十六进制是: 44434241, 写得清楚一点是: $44 $43 $42 $41; 还记得 Intel 等当下流行的 CPU 安排数据是倒着的吗?

    自己算算下一个, 用附件中的计算器即可.
  • 相关阅读:
    对“一道有趣的题目”的解答
    在Debian中使用Notify
    Debian服务器安装详细流程
    Lighttpd1.4.20源码分析之插件系统(1)plugin结构体和插件接口
    Lighttpd1.4.20源码分析之etag.c(h) HTTP/1.1中的Etag域
    Lighttpd1.4.20源码分析之bitset.c(h) 位集合的使用
    伸展树
    GCC中的弱符号与强符号
    Lighttpd1.4.20源码分析之fdevent系统(3) 使用
    Lighttpd1.4.20源码分析之插件系统(3)PLUGIN_TO_SLOT宏
  • 原文地址:https://www.cnblogs.com/del/p/1094873.html
Copyright © 2020-2023  润新知