В 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;
Сделайте ваш выбор!
Впрочем, при переносе этого кода вы можете воспользоваться возможностью изменить shl 2
а также shr 2
операции в арифметические операции для ясности.
Опция, о которой вы можете не знать, вообще не переводится. Скомпилируйте исходные файлы .c в объекты и статически свяжите их $LINK
,
И последний комментарий: вам стыдно за такую старую версию Delphi. Современные версии имеют $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;
Если у вас есть большие библиотеки с ++ для перевода, я бы посоветовал следовать рекомендациям Дэвида, в противном случае с этим более похожим на паскаль / Delphi способом проще работать.