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

标签 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;

最佳答案

您的代码不正确。你有一个额外的、错误的间接级别。这里您需要的是指向 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_arrayPint_array 转换时动态数组:

Pflt_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;

任君选择!


FWIW,为了清楚起见,您可以在移植此代码时捕获机会将 shl 2shr​​ 2 操作更改为算术操作。

您可能不知道的一个选项是根本不翻译。将原始 .c 文件编译为对象并使用 $LINK 静态链接它们。

最后的评论是,很遗憾您仍然使用如此旧版本的 Delphi。现代版本具有 $POINTERMATH 编译器选项。这允许 C 风格的指针算术和对标量变量的普通指针进行索引。对于此类移植任务来说是一个巨大的福音。

关于c++ - 如何在Delphi中进行C++参数数组指针运算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21820828/

相关文章:

c++ - 使用 decltype 编写复制和 move 函数

c - 尝试运行程序时出现段错误

c - 如果我要重复引用它们,是否应该将 C 数组值存储在局部变量中?

delphi - 如何使用 Chromium Embedded (CEF) 加载本地 html 文件?

c++ - 共享库中的 undefined symbol 与 g++

c++ - 仅具有特定方法的计算器。正常和递归

c++ - 从 bmp(或其他图像类型)中提取第 "n"个图像

javascript - 如何从具有类别和子类别属性的平面对象数组构建树数组

delphi - 如何在 Delphi 7 图像上绘制数字

delphi - delphi TFileStream“内存不足”