如何在德尔福中C++参数数组指针算术
How to do C++ parameter array pointer arithmetic in Delphi
在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_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;
任你挑选!
FWIW 为了清楚起见,您可能会在移植此代码时借此机会将shl 2
和shr 2
运算更改为算术运算。
您可能不知道的选项是根本不翻译。将原始 .c 文件编译为对象,并使用$LINK
静态链接它们。
最后一条评论是,你被困在这样一个旧版本的德尔福身上是一种耻辱。现代版本具有$POINTERMATH
编译器选项。这允许 C 样式指针算术和索引到标量变量的纯指针。对于此类移植任务来说是一个巨大的福音。
注意:这个答案不是试图回答手头的问题。大卫做到了这一点,并提出了处理指针算术的方法。
我不知道你有多少代码与这里介绍的代码相似。使用指针可能很麻烦,有时会导致类型转换时出现简单的错误。
一个更直接的 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 的建议,否则这种更像 pascal/Delphi 的方式更容易使用。
- 添加到数组指针
- C++语法差异:二维和一维数组(指针算术)
- 数组指针表示法C++(移动数组时)
- 复制后删除原始数组指针将前 3 个字节设置为 0
- C++访问指向结构的指针中的类数组指针
- C++编译时使用 constexpr 字符数组指针分配静态数组?
- std::flush可以用于将对象指针转换为其封闭数组指针吗
- 创建<int>对整数数组指针的矢量引用 (C++)
- 将 2D 数组指针传递给 C++ 中的函数
- 创建指针是否超过非数组指针的末尾,而不是从 C++17 中的一元运算符和未定义的行为派生?
- 队列数组指针 (C++)
- C++数组指针上的删除操作
- 对于循环不循环和检测字符数组 [指针和字符数组]
- 如何初始化数组指针对象
- 如何正确传递 2D 数组指针作为参数
- 从数组指针中获取怪异的数字
- 初始化std :: unique_ptr作为原始数组指针的初始化
- 将结构数组指针从C#传递到C
- STD :: Sort将数组指针设置为NULL
- C++数组指针错误无法将“int*”转换为“int**”