网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > Delphi
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
本月文章推荐
.原来的控件delphi7里何处寻?.
.性能vs结构.
.用Delphi5.0实现注册表监视.
.进程查看器1.3版开发后记.
.以最少的资源耗用,显示系统键状.
.在DELPHI中如何调用系统对话框.
.运行期间生成代码的动态执行.
.Delphi编程规范1.0.0.0.
.使用Topmost窗口,并且不会产生闪.
.Delphi中使用纯正的面向对象方法.
.使用ACTIVEX和DELPHI开发串口通讯.
.窗体的建立时机及缓冲的思想在in.
.如何在托盘图标实现漂亮的菜单.
.读取硬盘的物理序列号.
.如何使程序在运行时自动注册Acti.
.CRC32生成码表方法实现.
.项目迭代开发手记--文件分割存储.
.Delphi:易混淆的概念.
.再谈后台调用外部程序的完美实现.
.流的解压及压缩(代码精简高效).

Delphi2005学习笔记3——数组参数的研究

发表日期:2006-2-4


 

有如下代码:
  procedure Change(a:array of Int32);
  procedure Change0(var a:array of Int32);
type
  Ta = array[0..10] of Int32;
  procedure Change2(a:Ta);
  procedure Change3(var a:Ta);

var
  aa:Ta;
  bb:array of Int32;

implementation

{$AUTOBOX ON}

procedure Change(a:array of Int32);
begin
  a[0]:=123;
  a:=bb;
end;

procedure Change0(var a:array of Int32);
begin
  a[0]:=123;
  a:=bb;
end;

procedure Change2(a:Ta);
begin
  a[0]:=123;
  a:=bb;
end;

procedure Change3(var a:Ta);
begin
  a[0]:=123;
  a:=bb;
end;

然后执行下面的语句
SetLength(bb,11);bb[0]:=5678;

  aa := Ta(&Array.CreateInstance(typeof(Int32),11));
  aa[0]:=0;
  Change(aa);
  MessageBox.Show(aa[0].ToString());
  if &Object(aa)=&Object(bb) then MessageBox.Show('=');

  aa := Ta(&Array.CreateInstance(typeof(Int32),11));
  aa[0]:=0;
  Change0(aa);
  MessageBox.Show(aa[0].ToString());
  if &Object(aa)=&Object(bb) then MessageBox.Show('=');

  aa := Ta(&Array.CreateInstance(typeof(Int32),11));
  aa[0]:=0;
  Change2(aa);
  MessageBox.Show(aa[0].ToString());
  if &Object(aa)=&Object(bb) then MessageBox.Show('=');

  aa := Ta(&Array.CreateInstance(typeof(Int32),11));
  aa[0]:=0;
  Change3(aa);
  MessageBox.Show(aa[0].ToString());
  if &Object(aa)=&Object(bb) then MessageBox.Show('=');
结果发现 array of Int32 方式,可以改变数组元素的值,但不能改变数组变量中存储的数组首地址,输出123
var  array of Int32 既可以改变数组的值,又可以改变数组变量中存储的数组首地址,输出5678和=
Ta方式,不能改变数组元素的值,但是却很奇怪,aa和bb指向同一个数组,输出0和=
var Ta方式 可以改变数组元素的值,但是却不是5678而是123;但是aa和bb指向同一个数组,输出123和=


反汇编结果如下
method public static void Change(int32[] a) cil managed
{
      // Code Size: 13 byte(s)
      .maxstack 3
      L_0000: ldarg.0
      L_0001: ldc.i4.0
      L_0002: ldc.i4.s 123
      L_0004: stelem.i4
      L_0005: ldsfld int32[] WinForm.Units.WinForm::bb
      L_000a: starg.s a
      L_000c: ret
}

.method public static void Change0(int32[]& a) cil managed
{
      // Code Size: 14 byte(s)
      .maxstack 3
      L_0000: ldarg.0 
      L_0001: ldind.ref 
      L_0002: ldc.i4.0 
      L_0003: ldc.i4.s 123
      L_0005: stelem.i4 
      L_0006: ldarg.0 
      L_0007: ldsfld int32[] WinForm.Units.WinForm::bb
      L_000c: stind.ref 
      L_000d: ret 
}
.method public static void Change2(int32[] a) cil managed
{
      // Code Size: 42 byte(s)
      .maxstack 4
      .locals (
            int32 num1)
      L_0000: ldarg.0 
      L_0001: callvirt instance object [mscorlib]System.Array::Clone()
      L_0006: castclass int32[]
      L_000b: starg.s a
      L_000d: ldarg.0 
      L_000e: ldc.i4.0 
      L_000f: ldc.i4.s 123
      L_0011: stelem.i4 
      L_0012: ldsfld int32[] WinForm.Units.WinForm::bb
      L_0017: dup 
      L_0018: ldlen 
      L_0019: stloc.0 
      L_001a: ldarg.0 
      L_001b: ldloc.0 
      L_001c: ldc.i4.s 11
      L_001e: ble.s L_0023
      L_0020: ldc.i4.s 11
      L_0022: stloc.0 
      L_0023: ldloc.0 
      L_0024: call void [mscorlib]System.Array::Copy([mscorlib]System.Array, [mscorlib]System.Array, int32)
      L_0029: ret 
}


.method public static void Change3(int32[]& a) cil managed
{
      // Code Size: 31 byte(s)
      .maxstack 4
      .locals (
            int32 num1)
      L_0000: ldarg.0 
      L_0001: ldind.ref 
      L_0002: ldc.i4.0 
      L_0003: ldc.i4.s 123
      L_0005: stelem.i4 
      L_0006: ldsfld int32[] WinForm.Units.WinForm::bb
      L_000b: dup 
      L_000c: ldlen 
      L_000d: stloc.0 
      L_000e: ldarg.0 
      L_000f: ldind.ref 
      L_0010: ldloc.0 
      L_0011: ldc.i4.s 11
      L_0013: ble.s L_0018
      L_0015: ldc.i4.s 11
      L_0017: stloc.0 
      L_0018: ldloc.0 
      L_0019: call void [mscorlib]System.Array::Copy([mscorlib]System.Array, [mscorlib]System.Array, int32)
      L_001e: ret 
}

结论:
使用array of Int32 方式,实际上对应于C#的可变数目参数,即 params Int32[],
这种参数方式是传递的数组的首地址(即参数的值),而不是存放数组首地址的变量的地址
加上Var修饰,即加入ref修饰,传递的是存放数组首地址的变量的地址(即参数变量自身的地址)







使用Ta方式,则在函数内部对数组的值进行克隆,既不改变数组的首地址,也不改变原数组的值
加入var 修饰,好像传递的是变量自身的地址,这里还是没看懂是为什么。





对应的C#代码为

public static void Change(params int[] a)
{
      a[0] = 0x7b;
      a = WinForm.bb;
}

public static void Change0(params ref int[] a)
{
      a[0] = 0x7b;
      a = WinForm.bb;
}

public static void Change2(int[] a)
{
      a = (int[]) a.Clone();
      a[0] = 0x7b;
      int num1 = WinForm.bb.Length;
      if (num1 > 11)
      {
            num1 = 11;
      }
      Array.Copy(WinForm.bb, a, num1);
}

public static void Change3(ref int[] a)
{
      a[0] = 0x7b;
      int num1 = WinForm.bb.Length;
      if (num1 > 11)
      {
            num1 = 11;
      }
      Array.Copy(WinForm.bb, a, num1);
}
上一篇:IntToBin(2-16进制转换函数) 人气:6231
下一篇:如何减小应用程序(EXE)的大小? 人气:4417
浏览全部Delphi的内容 Dreamweaver插件下载 网页广告代码 祝你圣诞节快乐 2009年新年快乐