如何在Delphi中进行C ++参数数组指针运算

时间:2014-02-17 04:34:44

标签: c++ arrays delphi pointers delphi-7

在C ++中,您可以发送允许在数组上进行指针算术的参数。我需要能够在Delphi 7项目中做到这一点。我尝试这样做,但接收程序咳嗽。如果数组指针递增,c ^ [0]不应该在新的增量位置?

第一个过程调用makect()但是首先通过递增指针将指针移动到数组中更高的内存位置。但是,第二个过程,当设置为数组指针位置0时,不喜欢它。 (当然可能还有其他错误,但我想知道我是否正确这样做。)

为清晰起见,此处列出的

类型

type
  Pflt = ^flt;
  flt = double;

  Pflt_arr = ^flt_arr;
  flt_arr = array of flt;

  Pint_arr = ^int_arr;
  int_arr = array of integer;

构造

constructor TRefT.Create(const length:integer);
begin
  len := length;
  SetLength(_ip, 2 + (1 shl trunc(ln(length / 4.0) / ln(2.0) + 0.5) shr 1) );
  _ip[0] := 0;
  SetLength(_w, length shr 1);
end;


procedure TRefT.CF(buff: pflt_arr);
begin
  rdft(len, 1, buff, @_ip, @_w);
end;

调用程序

procedure TRefT.rdft(n:integer; isgn:integer; a:Pflt_arr; ip:Pint_arr; w:Pflt_arr);
var nw, nc: integer;
xi: flt;
begin
 nw := ip^[0];
 nc := ip^[1];
 if n > (nc shl 2) then
 begin
  nc := n shr 2;
  inc(w, nw);       <--attempt at pointer arithmetic
  makect(nc, ip, w); <-- C++ version is makect(nc, ip, w + nw);
 end;
end;

接收程序(增加数组);

procedure TRefT.makect(nc:integer; ip:Pint_arr; c:Pflt_arr);
var j, nch: integer;
  delta: flt;
begin
ip^[1] := nc;
if nc > 1 then
 begin
    nch := nc shr 1;
    delta := arctan(1.0) / nch;
    c^[0] := cos(delta * nch);  <-- coughs here!
    c^[nch] := 0.5 * c^[0];
    for j := 1 to nch do
     begin
        c^[j] := 0.5 * cos(delta * j);
        c^[nc - j] := 0.5 * sin(delta * j);
     end;
 end;
end;

2 个答案:

答案 0 :(得分:3)

您的代码不正确。你有一个额外的,错误的间接水平。你需要的是指向Double的静态数组的指针,而不是指向动态数组Double的指针。

请记住,动态数组是作为指向数组第一个元素的指针实现的。因此,就间接而言,您的类型等同于指向标量的指针。

一种方法是宣布像这样的类型

type
  Pflt_arr = ^Tflt_arr;
  Tflt_arr = array [0..0] of flt;

  Pint_arr = ^Tint_arr;
  Tint_arr = array [0..0] of Integer;

并确保对此代码禁用更改检查。

这将允许你写:

a^[i]
a的类型为Pflt_array

如果你写的话还有更多:

inc(a, n);

然后它会将地址a增加n*sizeof(a^) n*sizeof(Tflt_array) n*sizeof(flt)*Length(a^)) n*sizeof(flt)nc := ip^[1]; ,这正是您想要的。

当您将常量表达式作为索引提供时,这会中断。按照这一行:

1

此处编译器将反对0..0不在ip范围内。所以你不能两种方式。

在这种情况下,您似乎需要破解type Phuge_int_arr = ^Thuge_int_arr; Thuge_int_arr = array [0..(MaxInt div sizeof(Integer))-1] of Integer; 的前两个元素。您可以这样做:

nc := Phuge_int_arr(ip)^[1];

然后写:

type
  Pflt_arr = ^Tflt_arr;
  Tflt_arr = array [0..(MaxInt div sizeof(flt))-1] of flt;

感觉有点乱。


另一种方法是编写如下类型:

inc(Pflt(a), n);

适用于所有索引方案,并允许您启用范围检查。但它使指针递增更加困难。现在你必须写:

SetLength

总的来说,后一种方法可能是两种罪恶中较小的一种。


声明实际存储的代码仍应使用动态数组,Pflt_array等。当您需要Pint_arrayPflt_array(dyn_array) 投射动态数组时:

0..0

这是有效的,因为动态数组是作为指向数组第一个元素的指针实现的。


使用type Pflt = ^flt; flt = Double; Pflt_arr = ^Tflt_arr; Tflt_arr = array [0..0] of flt; Pint_arr = ^Tint_arr; Tint_arr = array [0..0] of Integer; Phuge_int_arr = ^Thuge_int_arr; Thuge_int_arr = array [0..(MaxInt div sizeof(Integer))-1] of Integer; .... constructor TRefT.Create(const length:integer); begin len := length; SetLength(_ip, 2 + (1 shl trunc(ln(length / 4.0) / ln(2.0) + 0.5) shr 1) ); SetLength(_w, length shr 1); end; procedure TRefT.CF(buff: pflt_arr); begin rdft(len, 1, buff, Pint_arr(_ip), Pflt_arr(_w)); end; procedure TRefT.rdft(n:integer; isgn:integer; a:Pflt_arr; ip:Pint_arr; w:Pflt_arr); var nw, nc: integer; xi: flt; begin nw := Phuge_int_arr(ip)^[0]; nc := Phuge_int_arr(ip)^[1]; if n > (nc shl 2) then begin nc := n shr 2; inc(w, nw); makect(nc, ip, w); end; end; procedure TRefT.makect(nc:integer; ip:Pint_arr; c:Pflt_arr); var j, nch: integer; delta: flt; begin Phuge_int_arr(ip)^[1] := nc; if nc > 1 then begin nch := nc shr 1; delta := arctan(1.0) / nch; c^[0] := cos(delta * nch); c^[nch] := 0.5 * c^[0]; for j := 1 to nch do begin c^[j] := 0.5 * cos(delta * j); c^[nc - j] := 0.5 * sin(delta * j); end; end; end; 变体,您的代码如下所示:

0..(MaxInt div sizeof(scalar))-1

或者使用type Pflt = ^flt; flt = Double; Pflt_arr = ^Tflt_arr; Tflt_arr = array [0..(MaxInt div sizeof(flt))-1] of flt; Pint_arr = ^Tint_arr; Tint_arr = array [0..(MaxInt div sizeof(Integer))-1] of Integer; .... constructor TRefT.Create(const length:integer); begin len := length; SetLength(_ip, 2 + (1 shl trunc(ln(length / 4.0) / ln(2.0) + 0.5) shr 1) ); SetLength(_w, length shr 1); end; procedure TRefT.CF(buff: pflt_arr); begin rdft(len, 1, buff, Pint_arr(_ip), Pflt_arr(_w)); end; procedure TRefT.rdft(n:integer; isgn:integer; a:Pflt_arr; ip:Pint_arr; w:Pflt_arr); var nw, nc: integer; xi: flt; begin nw := ip^[0]; nc := ip^[1]; if n > (nc shl 2) then begin nc := n shr 2; inc(Pflt(w), nw); makect(nc, ip, w); end; end; procedure TRefT.makect(nc:integer; ip:Pint_arr; c:Pflt_arr); var j, nch: integer; delta: flt; begin ip^[1] := nc; if nc > 1 then begin nch := nc shr 1; delta := arctan(1.0) / nch; c^[0] := cos(delta * nch); c^[nch] := 0.5 * c^[0]; for j := 1 to nch do begin c^[j] := 0.5 * cos(delta * j); c^[nc - j] := 0.5 * sin(delta * j); end; end; end; 的替代方案如下所示:

shl 2

接受你的选择!


为了清楚起见,您可以借此机会在移植此代码时将shr 2$LINK操作更改为算术运算。

您可能根本不知道的选项根本就没有翻译。将原始.c文件编译为对象,并使用$POINTERMATH静态链接它们。

最后一个评论是,你很遗憾你被困在这样一个旧版本的Delphi中。现代版本具有{{1}}编译器选项。这允许C样式指针算术和指向标量变量的普通指针索引。这种移植任务的巨大好处。

答案 1 :(得分:1)

注意:这个答案不是试图回答手头的问题。大卫这样做并提出了处理指针算术的方法。

我不知道你有多少代码与此处提供的代码类似。使用指针可能很麻烦,有时在类型转换时会导致简单的错误。

更直接的Delphi解决方案是使用动态数组,并使用开放数组声明方法。

您的示例的解决方案如下所示:

Type
 TRefT = class
 private
   len : Integer;
   _ip : array of integer;
   _w  : array of double;
 public
   Constructor Create(const length : integer);
   procedure CF(const buff : array of double);  // Or var
   procedure rdft(       n    : integer;
                         isgn : integer;
                   const a    : array of double;  // Or var
                     var ip   : array of integer;
                     var w    : array of double);
   procedure makect(     nc : integer;
                         nw : integer; // c array index offset
                     var ip : array of integer;
                     var c  : array of double);
 end;

constructor TRefT.Create(const length:integer);
begin
  len := length;
  SetLength(_ip, 2 + (1 shl trunc(ln(length / 4.0) / ln(2.0) + 0.5) shr 1) );
  SetLength(_w, length shr 1);
end;

procedure TRefT.CF(const buff: array of double);
begin
  rdft(len, 1, buff, _ip, _w);
end;

procedure TRefT.rdft(       n    : integer;
                            isgn : integer;
                      const a    : array of double;
                        var ip   : array of integer;
                        var w    : array of double);
var
  nw, nc: integer;
begin
  nw := ip[0];
  nc := ip[1];
  if n > (nc shl 2) then
  begin
    nc := n shr 2;
    makect(nc, nw, ip, w);
  end;
end;

procedure TRefT.makect(     nc : integer;
                            nw : integer;  // c array index offset
                        var ip : array of integer;
                        var c  : array of double);
var
  j, nch: integer;
  delta: double;
begin
  ip[1] := nc;
  if nc > 1 then
  begin
    nch := nc shr 1;
    delta := ArcTan(1.0) / nch;
    c[nw] := Cos(delta * nch);
    c[nch + nw] := 0.5 * c[nw];
    for j := 1 to nch do
    begin
      c[j + nw] := 0.5 * Cos(delta * j);
      c[nc - j + nw] := 0.5 * Sin(delta * j);
    end;
  end;
end;

如果您要翻译大型c ++库,我建议您遵循David的建议,否则这种更加方式/ Delphi更容易使用。