您的代码不正确。你有一个额外的、错误的间接级别。您需要的是指向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_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;
任君挑选!
为了清楚起见,您可能会在移植此代码时借此机会将 shl 2 和 shr 2 运算更改为算术运算。
您可能不知道的选项根本不翻译。将原始 .c 文件编译成对象并使用$LINK 静态链接它们。
最后一条评论是,很遗憾你被这么旧版本的 Delphi 困住了。现代版本具有$POINTERMATH 编译器选项。这允许 C 风格的指针算术和对标量变量的普通指针的索引。这样的移植任务是一个巨大的福音。