在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 回答
您的代码不正确 . 你有一个额外的,错误的间接水平 . 你需要的是指向
Double
的静态数组的指针,而不是指向Double
的动态数组的指针 .请记住,动态数组是作为指向数组第一个元素的指针实现的 . 因此,就间接而言,您的类型等同于指向标量的指针 .
一种方法是声明这样的类型
并确保禁用此代码的更改检查 .
这将允许你写:
当
a
的类型为Pflt_array
时 .如果你写的话还有更多:
那么它会将地址
a
递增n*sizeof(a^)
,这是n*sizeof(Tflt_array)
,这是n*sizeof(flt)*Length(a^))
,这是n*sizeof(flt)
,这正是你想要的 .当您将常量表达式作为索引提供时,这会中断 . 根据这一行:
这里编译器会反对
1
不在0..0
范围内 . 所以你不能两种方式 .在这种情况下,您似乎需要破解
ip
的前两个元素 . 您可以这样做:然后写:
感觉有点乱 .
另一种方法是编写如下类型:
这适用于所有索引方案,并允许您启用范围检查 . 但它使指针递增更加困难 . 现在你必须写:
总的来说,后一种方法可能是两种罪恶中较小的一种 .
声明实际存储的代码仍应使用动态数组,
SetLength
等 . 当需要Pflt_array
或Pint_array
强制转换动态数组时:这是有效的,因为动态数组是作为指向数组第一个元素的指针实现的 .
使用
0..0
变体,您的代码如下所示:或者使用
0..(MaxInt div sizeof(scalar))-1
的替代方案如下所示:随便挑选!
为了清楚起见,您可以利用此机会在移植此代码时将
shl 2
和shr 2
操作更改为算术运算 .您可能不知道的选项根本就没有翻译 . 将原始.c文件编译为对象,并使用
$LINK
静态链接它们 .最后一个评论是,你很难接受这样一个旧版本的Delphi . 现代版本具有
$POINTERMATH
编译器选项 . 这允许C样式指针算术和指向标量变量的普通指针索引 . 这种移植任务的巨大好处 .注意:这个答案不是试图回答手头的问题 . 大卫做到了这一点并提出了处理指针算术的方法 .
我不知道你有多少代码与这里提供的代码类似 . 使用指针可能很麻烦,有时在类型转换时会导致简单的错误 .
更直接的Delphi解决方案是使用动态数组,并使用开放数组声明方法 .
您的示例的解决方案如下所示:
如果您要翻译大型c库,我建议您遵循David的建议,否则这种更加方便/ Delphi的方式更容易使用 .