我有以下代码示例编译在delphi xe5 update 2中.
procedure TForm1.FormCreate(Sender: TObject);
var i,t:Integer;
    buf: array [0..20] of TPair<Integer,Integer>;
begin
  t := 0;
  for i := Low(buf) to High(buf) do begin
    ShowMessage(
      Format(
        'Pointer to i = %p;'#$d#$a+
        'Pointer to buf[%d].Key = %p;'#$d#$a+
        'Pointer to buf[%d].Value = %p;'#$d#$a+
        'Pointer to t = %p',[@i,i,@(buf[i].Key),@(buf[i].Value),@t]
      )
    );
    buf[i].Key := 0;
    buf[i].Value := 0;
    t := t + 1;
  end;
end;

如果我运行它,它会显示变量的地址.
变量i和t在buf的内存范围内具有地址!
当ireaches 3时,赋值buf [i] .Value:= 0;覆盖i的前3个字节和t的最后一个字节.这导致无限循环,因为当它达到3时,我得到重置为0.
如果我用SetLength(buf,20)自己分配内存;一切安好.

图片显示了我的意思.

我的设置:

> Windows 7 64位
> Delphi XE 5 Update 2
>调试配置32位

奇怪,不是吗?
有人可以重现吗?
是delphi编译器中的错误吗?

谢谢.

编辑:
这是同样的例子,但也许更好地了解我的意思:

和btw:对不起,我的英文不好)

解决方法

这肯定是一个编译器的bug.它只影响在堆栈上分配的TPair阵列.例如,这个编译和运行正常:
program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Generics.Collections;

var i:Integer;
    buf: array [0..20] of TPair<Integer,Integer>;
begin
  for i := Low(buf) to High(buf) do begin
    buf[i].Key := 0;
    buf[i].Value := 0;
  end;
end.

但是,这显示了错误:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Generics.Collections;    

procedure DoSomething;
var i:Integer;
    buf: array [0..20] of TPair<Integer,Integer>;
begin
  for i := Low(buf) to High(buf) do begin
    buf[i].Key := 0;
    buf[i].Value := 0;
  end;
end;

begin
  DoSomething;
end.

编译器似乎错误地计算了TPair< Integer,Integer>的大小.编译的汇编显示如下前言:

Project1.dpr.14: begin
00445C50 55               push ebp
00445C51 8BEC             mov ebp,esp
00445C53 83C4E4           add esp,-$1c  //***  Allocate only 28 bytes (7words)
Project1.dpr.15: for i := Low(buf) to High(buf) do begin
00445C56 33C0             xor eax,eax
00445C58 8945FC           mov [ebp-$04],eax
Project1.dpr.16: buf[i].Key := 0;
00445C5B 8B45FC           mov eax,[ebp-$04]
00445C5E 33D2             xor edx,edx
00445C60 8954C5E7         mov [ebp+eax*8-$19],edx
Project1.dpr.17: buf[i].Value := 0;
00445C64 8B45FC           mov eax,[ebp-$04]
00445C67 33D2             xor edx,edx
00445C69 8954C5EB         mov [ebp+eax*8-$15],edx
Project1.dpr.18: end;
00445C6D FF45FC           inc dword ptr [ebp-$04]
Project1.dpr.15: for i := Low(buf) to High(buf) do begin
00445C70 837DFC15         cmp dword ptr [ebp-$04],$15
00445C74 75E5             jnz $00445c5b
Project1.dpr.19: end;
00445C76 8BE5             mov esp,ebp
00445C78 5D               pop ebp
00445C79 C3               ret 
00445C7A 8BC0             mov eax,eax

编译器只在堆栈上分配了7个双字.第一个是整数i,只留下分配给TPair阵列的6个双词,这是不够的(SizeOf(TPair <整数,整数)等于8 - >两个双字).在第三次迭代中,mov [ebp eax * 8- $15],edx(即:buf [2] .Value)运行到i的堆栈位置,并将其值设置为零. 您可以通过在堆栈上强制足够的空间来演示一个工作程序:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Generics.Collections;


procedure DoSomething;
var i:Integer;
    fixalloc : array[0..36] of Integer; // dummy variable
                                        // allocating enough space for
                                        // TPair array
    buf: array [0..20] of TPair<Integer,Integer>;
begin
  for i := Low(buf) to High(buf) do begin
    buf[i].Key := i;
    buf[i].Value := i;
  end;
end;

begin
  DoSomething;
end.

这是在XE2中进行测试,但是如果您还看到问题,似乎至少还会持续XE5.

delphi – 局部变量和TPair阵列 – 内存分配的奇怪行为的更多相关文章

  1. ios – 我在哪里可以找到用于创建IPad应用程序的Delphi资源?

    我之前一直在使用Delphi并且一直都是Windows家伙.我的妻子为我的生日买了一台新的iPad,我昨晚第一次使用它.哇!…

  2. 如何从命令行部署OSX或IOS Delphi项目?

    我正在使用像这样的脚本构建我的Delphi应用程序现在我想添加一个选项将应用程序部署到OSX系统修改这样的脚本,那么可以从命令行部署OSX或IOSDelphi项目吗?

  3. Swift基础语法: 27 - Swift的全局变量和局部变量, 类型属性, 获取和设置类型属性的值

    类型属性用于定义特定类型所有实例共享的数据,比如所有实例都能用的一个常量,或者所有实例都能访问的一个变量.对于值类型可以定义存储型和计算型类型属性,对于类则只能定义计算型类型属性,值类型的存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样定义成变量属性.PS:跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。

  4. [翻译]Swift编程语言——函数

    Swift的标准化函数语法足够用来表述无论是C风格的无参函数,还是复杂的OC风格的具有本地和外部参数的方法。每个Swift的函数都有类型,类型包括了函数的参数类型和返回值类型。为了让这个函数看起来更简洁,可以将讯息创建和返回语句组合在一行实现:函数的参数和返回值Swift的函数参数以及返回值是非常灵活的。写那个名字一次,在它的前面加上井号就可以,这个告诉Swift这个参数的局部名称和外部名称相同。

  5. Swift学习:2.6 函数

    Swift统一的函数语法足够灵活,可以用来表示任何函数,包括从最简单的没有参数名字的C风格函数,到复杂的带局部和外部参数名的Objective-C风格函数。在Swift中,每个函数都有一种类型,包括函数的参数值类型和返回值类型。下面这个函数就是一个无参函数,当被调用时,它返回固定的String消息:尽管这个函数没有参数,但是定义中在函数名后还是需要一对圆括号。第二个函数printWithoutCounting调用了第一个函数,但是忽略了它的返回值。

  6. 如何检查Android和iOS上的网络是否可用(Delphi XE5)

    解决方法试试这个:

  7. 关于全局变量和局部变量的那些事

    关于全局变量和局部变量的那些事,有哪些事呢?不要走开,接下来将详细介绍,感兴趣的朋友可以了解下哦

  8. JavaScript把局部变量变成全局变量的方法

    这篇文章主要介绍了JavaScript把局部变量变成全局变量的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  9. phpinfo() 中 Local Value(局部变量)Master Value(主变量) 的区别

    这篇文章主要介绍了phpinfo() 中 Local Value(局部变量)Master Value(主变量) 的区别,需要的朋友可以参考下

  10. PHP变量作用域(全局变量&amp;局部变量)&amp;global&amp;static关键字用法实例分析

    这篇文章主要介绍了PHP变量作用域(全局变量&局部变量)&global&static关键字用法,结合实例形式分析了PHP全局变量与局部变量的作用域,以及global、static关键字功能与使用技巧,需要的朋友可以参考下

随机推荐

  1. delphi – 主窗口按进程名称处理

    DelphiXe,Win7x64如何从进程名称(exe文件的完整路径)获取主窗口句柄,或至少一个类或窗口名称(如果该进程只有一个窗口).例:解决方法我同意Petesh的说法,你需要枚举顶级窗口并检查创建它的进程的模块文件名.为了帮助您开始枚举顶级窗口,这是一个delphi实现.首先,当你回调给你时,你需要一些与EnumWindows方法通信的方式.为此声明一条记录,该记录将保存您要查找的模块的文件

  2. 如何在Delphi中纯粹通过RTTI信息(即不使用任何实际对象实例)获取TObjectList的子项类型?

    我正在使用RTTI实现用于流式传输任意Delphi对象的通用代码,并且为了使其工作(更具体地说,为了使加载部分工作),我需要以某种方式获得TObjectList的子项类型<T>不使用任何实际对象实例的字段.要求不使用任何实际对象实例的明显原因是,在从流加载对象的情况下(仅基于要加载的对象的类类型的知识),我将不会有任何实例在加载完成之前完全可用–我宁愿只能访问相关类的纯RTTI数据.我希望能

  3. inno-setup – Inno Setup – 安装程序背景图片

    图像作为安装程序背景如何用inno5.5.9做到这一点?

  4. inno-setup – Inno Setup – 如何添加多个arc文件进行解压缩?

    使用InnoSetup解压缩弧文件.我希望有可能解压缩多个arc文件以从组件选择中安装文件(例如).但仍然显示所有提取的整体进度条.这可能吗?的回答的修改预备是相同的,参考其他答案.在ExtractArc中,为要提取的每个存档调用AddArchive.

  5. delphi – 如何在DataSet的帮助下在TAdvStringGrid中显示数据库中的BLOB图像

    解决方法CreateBlobStream正在创建一个TStream对象,而不是TMemoryStream.由于您不想将JPG写入数据库,因此应使用bmRead而不是bmReadWrite.我不习惯sqlite,但你必须确保使用合适的二进制日期类型.为了确保存储的图像真的是JPG,您应该编写JPG以进行测试,例如:

  6. inno-setup – 在Inno Setup的Code部分下载程序后运行程序

    如何运行我通过Internet下载的应用程序,在代码部分中使用,并等待该应用程序完成运行.我有,使用InnoTools下载程序,下载这两个文件,我想,在第二个完成下载后运行该下载,或jdk-8u111-windows-x64.exe,然后继续安装.解决方法使用其他下载插件,而不是ITD(请参阅下面的原因).例如,InnoDownloadPlugin.当您包含idp.iss时,它定义了一个全局IDP

  7. progress-bar – Inno Setup Run部分的简单进度页面

    我的安装程序非常简单,它基本上是:>欢迎页面>进展页面>最终页面欢迎页面和最终页面是标准页面.在Progress页面,我正在静默安装一堆其他程序.实际的脚本是在[Run]部分中安装每个程序.问题是酒吧达到100%然后停留在那里.我只能更改消息文本.我想要实现的是使用Pascal脚本显示进度,例如:这样我就可以显示更准确的进度条.这就是我所拥有的:问题是,当我构建安装程序时,它不显示欢迎页面.我做错了什么?

  8. delphi – 如何使“显示/隐藏桌面图标”设置生效?

    下面的代码调用SHGetSetSettings函数来隐藏桌面图标但它只是从视图菜单中取消选中“显示桌面图标”.我打电话给SHChangeNotify;更新桌面,但这不起作用?解决方法isa,要刷新桌面,您可以将F5键发送到progman窗口隐藏桌面图标的另一种方法是再次显示

  9. inno-setup – Inno Setup – 避免显示子安装程序的文件名

    我试图使用InnoSetup–Howtohidecertainfilenameswhileinstalling?(FilenameLabel)的想法Theonlysuresolutionistoavoidinstallingthefiles,youdonotwanttoshow,usingthe[Files]section.Installthemusingacodeinstead.UsetheEx

  10. inno-setup – Inno Setup磁力链接下载实施

    我目前正在使用InnoDownloadPlugin为我的安装程序下载文件,这个问题最大的问题是faila正确下载文件.因为连接不良等诸多原因.我想添加一种替代方法来下载文件,因此用户可以选择是否需要常规方式或torrent方式.我知道我可以使用aria2c.exe应用程序(https://aria2.github.io/),有人可以帮我实现它的inno设置代码吗?我需要的是使用torrent(ar

返回
顶部