与C进行互操作时,我经常发现自己被赋予了指向数组的指针。 Chapel当前让我将此指针视为1D 0索引数组。但是,在某些情况下,我想将此指针视为Chapel数组(例如具有多维域)。在教堂中,最惯用的方式是什么?
我可能试图通过将C指针包装在一个类(具有一个域)中,并定义this
和these
(串行和并行)方法来做到这一点,以便可以索引和遍历全班。为了实现这一点,具有将域中的索引映射到0索引位置的功能将很有用。有这样的内置功能吗?
答案 0 :(得分:4)
不幸的是,似乎没有一个适用于每个域的功能。 DefaultRectangularArr
在幕后使用了称为getDataIndex
的方法来执行此计算,看起来其他数组类型依赖于内部存储类上定义的类似方法。看起来这些在域本身上不可用。我怀疑依靠这些方法都是不明智的,因为无论如何它们可能会作为实施调整的一部分而更改。
我们希望最终可以使用为互操作性定义的makeArrayFromPtr
函数之类的东西将最终描述的指针包装在Chapel数组中。不幸的是,该功能目前仅支持1D 0索引数组,但目前正在努力扩展我们对数组互操作性的支持。我希望该函数能够调整其参数或为多维数组定义另一个版本,我们仍在弄清楚这一点。
答案 1 :(得分:4)
我很好奇我是否可以毫不费力地欺骗Chapel数组引用C中分配的缓冲区。我能够做到,但对结果并不感到骄傲。具体来说:
请记住这些注意事项,这是一个简单的C标头,其中公开了一些从Chapel调用的简单例程。第一个分配一个平凡的9元素数组;第二个释放了它的论点。
#include <stdlib.h>
double* getDataPtr() {
double* dataPtr = (double*)malloc(9*sizeof(double));
dataPtr[0] = 1.1;
dataPtr[1] = 1.2;
dataPtr[2] = 1.3;
dataPtr[3] = 2.1;
dataPtr[4] = 2.2;
dataPtr[5] = 2.3;
dataPtr[6] = 3.1;
dataPtr[7] = 3.2;
dataPtr[8] = 3.3;
return dataPtr;
}
void freeDataPtr(double* ptr) {
free(ptr);
}
这是调用它的Chapel代码,然后将C指针强制插入具有适当大小和从0开始的索引的现有数组:
//
// Declare a Chapel array. Note that this program will only work as
// written if it uses 0-based indexing.
//
var A: [0..2, 0..2] real;
//
// testit.h is the C code above. It defines a simple C stub that returns a pointer
// to floating point data.
//
require "testit.h";
//
// Here are the key routines that testit.h exposes back to Chapel to
// get and free a pointer to floating point data.
//
extern proc getDataPtr(): c_ptr(real);
extern proc freeDataPtr(ptr: c_ptr(real));
//
// Grab the pointer from C
//
const myCPtr = getDataPtr();
//
// Save two pointer values defined in A's descriptor. Note that these
// are not part of its public interface, so are not recommended for
// typical users and could change / break at any future point.
//
const saveData = A._value.data;
const saveShiftedData = A._value.shiftedData;
//
// Replace these pointers with the one we got from C.
//
A._value.data = (myCPtr: _ddata(real));
A._value.shiftedData = (myCPtr: _ddata(real));
//
// print out A, "proving" that we're referring to the data from C
//
writeln(A);
//
// restore the original pointers to avoid having Chapel try to free
// the C memory / leak the Chapel memory.
//
A._value.data = saveData;
A._value.shiftedData = saveShiftedData;
//
// Free the C data
//
freeDataPtr(myCPtr);
Chapel writeln(A)
语句的输出为:
1.1 1.2 1.3
2.1 2.2 2.3
3.1 3.2 3.3
我认为向Chapel的GitHub issues page提出功能请求是完全合理的,该提议提出了一种更好的面向用户的界面来采用这样的C指针,尽管这是一种更好且更正式的方式。
答案 2 :(得分:1)
下面可能有一种略有不同的方法。这里的缺点是这不是Chapel数组,但确实允许索引/迭代,就像Chapel数组一样。这无法处理跨步或非零对齐,并且没有进行边界检查。
prototype module CPtrArray {
use SysCTypes;
record CPtrArray {
type eltType;
param rank : int;
const first : rank*int;
const blk : rank*int;
var data : c_ptr(eltType);
proc init(type t, D : domain, ptr : c_ptr(t)) {
this.eltType = t;
this.rank = D.rank;
this.first = D.first;
var blktmp : rank*int;
blktmp(rank) = 1;
if (rank > 1) {
for param idim in (rank-1)..1 by -1 {
blktmp(idim) = blktmp(idim+1)*D.shape(idim+1);
}
}
this.blk = blktmp;
this.complete();
data = ptr;
}
proc getDataOffset(ndx : rank*int) : int {
var offset = ndx(rank)-first(rank);
if (rank > 1) {
for param idim in 1..(rank-1) do
offset += (ndx(idim)-first(idim))*blk(idim);
}
return offset;
}
inline proc this(ndx : rank*int) ref {
return data[getDataOffset(ndx)];
}
inline proc this(i:int ...rank) ref {
return this(i);
}
// Should provide iterators as well.
}
}
使用它的简单测试程序:
use CPtrArray;
var A : [0.. #10] real;
forall ii in 0.. #10 do A[ii] = ii+1.0;
writeln(A);
var ptr = c_ptrTo(A[0]);
// Code for testing the array class goes here
const D = {1.. #5, 3.. #2};
var A1 = new CPtrArray(real, D, ptr);
for ndx in D {
writeln(ndx," ",A1[ndx]);
}