Delphi/FreePascal用指针访问数组的异同

前一段业余移植一个C写的 Total Commander 插件到 Double Commander, 后者是用FreePascal写的,虽然也可以直接用C来做这个插件,但俺还是有兴趣用freepascal重写一遍。最开始是用Lazarus 做IDE来写,为偷懒基本上是C函数到pascal函数来移,结构打算后面再调整,但移植完两个函数后调测时觉得Lazarus 这个IDE的调试功能实在太差,于是又改到先用Delphi 7来编译,于是发现了这两者在数组、指针方面的一些差异。刚才在Delphi 7, Delphi 2009和Freepascal 2.2.4上做了一下对比,结果如下:


Delphi 7

    procedure TestIntArray;
    var
      arr : array[0..10] of integer;
      p : PInteger;
      i : integer;
      s: string;
    begin
      for i:=0 to Length(arr)-1 do
        arr[i] := i + 1000;
    
    //  p := arr;  //error: Incompatible types: 'Array' and 'PInteger'
      p := @arr;
      Writeln(IntToStr(p^));
      p := @arr[0]; //the same effect with above line?
      Writeln(IntToStr(p^));
    
    //  Writeln(IntToStr(p[2]));     //error: Array type required
    
    //  p := p + 1;  //error: Operator not applicable to this operand type
      Inc(p);
    
    //  Writeln(IntToStr((p+1)^)); //error: Operator not applicable to this operand type
      Writeln(IntToStr(p^));
    
      Readln(s);
    end;

 可以看出

  * 不能象C语言那样直接将数组赋值给指针 ( p := arr ),只能 ( p := @arr 或者 p := @arr[0]  ),同样 p[2]也不是一个合法的表达式(错误信息为Array type required)
  * 指针不能直接与数字做运算,比如p + 1这是不合法的(错误信息是Operator not applicable to this operand type),只能inc(p)或者dec(p),如果要增2就inc(p, 2)

但字符数组是个例外:

    procedure TestCharArray;
    var
      arr : array[0..10] of Char;
      p : PChar;
      i : integer;
      s: string;
    begin
      for i:=0 to Length(arr)-1 do
        arr[i] := Chr(Ord('a') + i);
    
      p := arr;  //OK!
      p := @arr;
      Writeln(p^);
      p := @arr[0]; //the same effect with above line?
      Writeln(p^);
    
      p := p + 1;  //OK!
      Inc(p);
      Writeln(p[2]); //OK!
    
      Writeln((p+1)^); //OK!
    
      Readln(s);
    end;

这里,p := arr, p:= p + 2, p[2] 这几个表达式都合法了,并且结果与期望一致。

FreePascal (2.2.4)

    procedure TForm1.TestIntArray;
    var
      arr : array[0..10] of integer;
      p : PInteger;
      i : integer;
      s: string;
    begin
      for i:=0 to Length(arr)-1 do
        arr[i] := i + 1000;
    
      p := arr;  //OK!
      Memo1.Lines.Add(IntToStr(p^)); //output: 1000
      p := @arr;
      Memo1.Lines.Add(IntToStr(p^)); //output: 1000
      p := @arr[0]; //OK!
      Memo1.Lines.Add(IntToStr(p^)); //output: 1000
    
      Memo1.Lines.Add(IntToStr(p[2])); //OK! output: 1002
    
      p := p + 1;  //OK!
      Inc(p);
    
      Memo1.Lines.Add(IntToStr((p+1)^)); //OK! //output: 1003
      Memo1.Lines.Add(IntToStr(p^));
    
    //  Readln(s);
    end;

 

即使对于整数数组(其它也是,包括字符串数组),p := arr, p:= p + 2, p[2] 这几个表达式也都是合法的。

Delphi 2009

在默认的选项下,Delphi 2009与Delphi 7相同,上述三种表达式都不支持。但可以打开一个编译选项$POINTERMATH:   

   {$POINTERMATH ON}
    procedure TestIntArray;
    var
      arr : array[0..10] of integer;
      p : PInteger;
      i : integer;
      s: string;
    begin
      for i:=0 to Length(arr)-1 do
        arr[i] := i + 1000;
    
    //  p := arr;  //error: Incompatible types: 'Array' and 'PInteger'
      p := @arr;
      Writeln(IntToStr(p^));{$POINTERMATH ON}
    procedure TestIntArray;
    var
      arr : array[0..10] of integer;
      p : PInteger;
      i : integer;
      s: string;
    begin
      for i:=0 to Length(arr)-1 do
        arr[i] := i + 1000;
    
    //  p := arr;  //error: Incompatible types: 'Array' and 'PInteger'
      p := @arr;
      Writeln(IntToStr(p^));
      p := @arr[0]; //the same effect with above line?
      Writeln(IntToStr(p^));
    
      Writeln(IntToStr(p[2])); //OK in D2009
    
      p := p + 1;  //OK in D2009
      Inc(p);
    
      Writeln(IntToStr((p+1)^)); //OK in D2009
    //  Writeln(IntToStr(p^));
    
      Readln(s);
    end;
      p := @arr[0]; //the same effect with above line?
      Writeln(IntToStr(p^));
    
      Writeln(IntToStr(p[2])); //OK in D2009
    
      p := p + 1;  //OK in D2009
      Inc(p);
    
      Writeln(IntToStr((p+1)^)); //OK in D2009
    //  Writeln(IntToStr(p^));
    
      Readln(s);
    end;

 
p := arr仍然是不合法的表达式,但 p + 2 和 p[2] 都可以了。

posted @ 2010-06-14 22:51  巴蛮子  阅读(1586)  评论(0)    收藏  举报