这有点延续了我之前的问题,found here.本质上,我试图用一个基本的例子来测试dll /函数,但是我得到了' E2010 - 不兼容的类型:AInteger / ADouble和Set '和' E1012 - 常量表达式违反了我的数组上的子范围'错误。我(有点)得到它想说的,但无法弄清楚我应该修复什么。例如:
var
n: Integer;
Ap, Ai: AInteger;
Ax, b: ADouble;
begin
// Initializations
n := 5;
Ap := [0, 2, 5, 9, 10, 12]; <- E2010
Ai := [0, 1, 0, 2, 4, 1, 2, 3, 4, 2, 1, 4]; <- E2010
Ax := [2, 3, 3, -1, 4, 4, -3, 1, 2, 2, 6, 1]; <- E2010 and E1012
b := [8, 45, -3, 3, 19]; <- E1012
AInteger
和ADouble
类型是我的数组:
ADouble = array[0..High(Integer) div SizeOf(Double) - 1] of Double;
AInteger = array[0..High(Integer) div SizeOf(Integer) - 1] of Integer;
并且应该以这种方式初始化(根据Rudy的Delphi页面和其他C-to-Pascal源代码),因为它们在C中写为double Ax[]
。我确信有一些简单的我做错了或者可以为了测试我的dll而改变,但也许我谷歌搜索错误,因为我找不到一个示例/解决方案。所以,问题形式:
Q1 :E1012是指
“如果你做这些事情 [AInteger和ADouble] ,请务必不要太靠近 高(整数),因为编译器可能会抱怨数据 结构太大了。“(引自Rudy的页面)
Q2 :我该如何更改此代码?
提前感谢您的帮助。
答案 0 :(得分:8)
你可以用这样的语法来做到这一点。
如此定义数组:
ADouble = array[0..High(Integer) div SizeOf(Double) - 1] of Double;
将初始化整个32位RAM大小的整数数组!您永远无法分配这样的变量(仅在Win64上,但您将使用4 GB的RAM仅存储6个整数)! :)
您的阵列需要动态,即在运行时更改大小。所以你必须这样定义:
type
AInteger = array of integer;
此类数组无法在语言的当前状态AFAIR中直接分配。
所以你需要编写这样一个函数:
procedure SetArray(var dest: AInteger; const values: array of integer);
begin
SetLength(dest,Length(values));
move(values[0],dest[0],length(values)*sizeof(integer));
end;
您可以使用常量数组作为源:
const
C: array[0..5] of Integer = (0, 2, 5, 9, 10, 12);
var
Ap: AInteger;
begin
SetArray(Ap,C);
或使用开放数组参数:
var
Ai: AInteger;
begin
SetArray(Ai,[0, 2, 5, 9, 10, 12]);
当然,第二种解决方案听起来更接近您的期望。
更新:对于较新版本,您当然可以使用动态数组构造函数,如下所示:
var
Ai: AInteger;
begin
Ai := AInteger.Create(0,2,5,9,10,12);
答案 1 :(得分:2)
在我看来,好像你有用C编写的稀疏求解器代码,并试图将它链接到你的Delphi程序。我认为你宣布外部进口的方式存在根本问题。我没有回答您直接提出的问题,而是向您展示我认为是宣布和调用此类外部进口的正确方式。
我要说的第一件事是你声明的大型静态数组类型不是你需要的。这些数组类型有时可能很有用,但只有在将另一个数组转换为PADouble = ^ADouble
时才有用。在您的情况下,您根本不需要这些数组,我建议您删除它们。
我将假设你正在调用一个名为solve
的函数,该函数需要n
,nz
,Ap
,Ai
,{{1 }和Ax
作为输入参数,并返回b
作为输出参数。函数返回x
,x
其中A*x=b
是由A
,n
和{{1}指定的Ap
维方形稀疏矩阵}。 Ai
参数指定非零元素的数量。毫无疑问,实际功能的细节会有所不同,但概念也是一样的。例如,从Ax
推断nz
是很常见的,但这些细节供您解决。
我建议你声明函数接收参数作为第一个元素的指针。所以函数声明如下所示:
nz
然后你需要填充你的稀疏矩阵数组。将这些声明为动态数组:
Ap[n]
我希望您在运行时只知道function solve(
n: Integer;
nz: Integer;
Ap: PInteger;
Ai: PInteger;
Ax: PDouble;
b: PDouble;
x: PDouble
): Integer; cdecl; external;
,var
Ap: TArray<Integer>;
Ai: TArray<Integer>;
Ax: TArray<Double>;
....
SetLength(Ap, n);
Ap[0] := ...;
....
SetLength(Ai, nz);
Ap[0] := ...;
....
SetLength(Ax, nz);
Ax[0] := ...;
....
等的值,并且使用循环等填充矩阵的内容。问题中的代码可能是测试代码,用于尝试测试外部代码。 Arnaud的回答为您提供了有关如何填充动态数组的合理建议。
您还需要初始化n
和nz
:
b
现在您可以调用该函数:
x
最后一点,转换使用通用数组。由于您使用的是现代Delphi,我建议您使用通用动态数组。因此,您应该使用var
b: TArray<Double>;
x: TArray<Double>;
....
SetLength(b, n);
b[0] := ...;
....
SetLength(x, n);
// no need to initialise values of x[i] since it is the output
而不是var
retval: Integer;
....
retval := solve(n, nz, PInteger(Ap), PInteger(Ai), PDouble(Ax),
PDouble(b), PDouble(x));
。原因是泛型类型与旧式动态数组具有不同的类型兼容性规则。例如,在上面的代码中,array of ...
和TArray<...>
是分配兼容的。但如果他们被宣布为这样:
b
然后他们不会兼容任务。您可以通过声明类型x
来解决该问题。但是,如果使用泛型数组,则可以使用通用容器类(如var
b: array of Double;
x: array of Double;
),而不是返回类型TDoubleArray = array of Double
的值,这些值很容易消耗。
我知道这不是你提出的问题,但我觉得它可能对你有用。
答案 2 :(得分:0)
此问题与开放数组无关,因此请从您的问题中删除该标记。
您正在使用的括号语法声明Set
个值,这基本上是一种特殊类型的位掩码,其中每个位对应于该位置的值。换句话说,[0, 2, 5, 9, 10, 12]
是包含6个元素的Set of Integer
,其中位0指的是值0,位1指的是值2,位2指的是值5,依此类推。无法像您尝试的那样将Set
直接分配给数组。