负数组索引和内存中的放置(指向)
在 fortran 中,您可以声明具有任何合适(整数)范围的数组,例如:
real* 8 array(-10:10)
我相信 fortran 在通过引用传递时,将始终将 array(1) 作为引用传递,但我不确定。
我正在使用 fortran 指针,并且我相信 fortran 指向“第一个”元素地址,即数组(1),而不是数组(-10)。不过我不确定。
Fortran 如何处理内存中的负数组索引?它是实现定义的吗?
编辑:为了添加更多细节,我通过使用 fortran 指针指向地址,将 malloc 块从 C 传递到 fortran,这是通过从 CIe C 中调用 fortran 例程来完成的:
void * pointer = malloc(blockSize*sizeof(double));
fortranpoint_(pointer);
Fortran 点例程如下所示:
real*8 :: target block(5, -6:6, 0:0)
real*8 :: pointer array(:,:,:)
entry fortranPoint(block)
array => block
return
问题是,有时当它稍后尝试访问时会说:
array(1, -6, 0)
我不确定这是访问块开头还是之前某处的地址。我现在认为这是实现定义的,但想知道每个实现的细节。
In fortran you can declare an array with any suitable (integral) range, for example:
real* 8 array(-10:10)
I believe that fortran, when passing by reference, will always pass around array(1) as the reference, but I'm not sure.
I'm using fortran pointers, and I believe that fortran is pointing the "1st" element address, i.e. array(1), not array(-10). However I'm not sure.
How does Fortran deal with negative array indexing in memory? And is it implimentation defined?
Edit: To add a little more detail, I'm passing a malloc'd block from C to fortran by means of using a fortran pointer to point at the the address, which is done by calling a fortran routine from within C. I.e. C goes:
void * pointer = malloc(blockSize*sizeof(double));
fortranpoint_(pointer);
And the fortran point routine looks like:
real*8 :: target block(5, -6:6, 0:0)
real*8 :: pointer array(:,:,:)
entry fortranPoint(block)
array => block
return
The problem is that sometimes when it later tries to access say:
array(1, -6, 0)
I am not sure if this is accessing the address at the beginning of the block or somewhere before it. I now think this is implementation defined, but would like to know the details of each implementation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Fortran 数组参数 ABI 取决于编译器,也许更重要的是,取决于被调用的过程是否具有显式接口或隐式接口。
对于隐式接口,通常传递第一个元素的地址[1]。在被调用方中,该过程然后根据数组虚拟参数的声明方式添加一个偏移量。例如,如果数组虚拟参数被声明为 somearray(-10:10),则对 somearray(x) 的引用计算为
如果过程具有显式接口,通常会传递数组描述符结构而不是第一个元素的地址。在这个结构中,被调用者可以找到有关每个维度边界的信息,当然还有指向实际数据的指针,使其能够计算正确的偏移量,类似于隐式接口的情况。
[1] 请注意,这是内存中的第一个元素,即每个维度的最低索引。不是 somearray(1),无论数组是如何声明的。
要回答您更新的问题,对于 C/Fortran 互操作性,请使用当今广泛使用的 ISO_C_BINDING 功能。这提供了一种在 C 和 Fortran 之间传递信息的标准化方法。
Fortran array argument ABI depends on the compiler, and perhaps more crucially, on whether the called procedure has an explicit or implicit interface.
For an implicit interface, typically the address of the first element is passed [1]. In the callee, the procedure then adds an offset depending on how the array dummy argument is declared. E.g. if the array dummy argument is declared somearray(-10:10), then a reference to somearray(x) is calculated as
If the procedure has an explicit interface, typically an array descriptor structure is passed rather than the address of the first element. In this structure, the callee can find information on the bounds of each dimension and, of course, a pointer to the actual data, allowing it to calculate the correct offset, similarly to the case of an implicit interface.
[1] Note that this is the first element in memory, that is, the lowest index for each dimension. Not somearray(1) regardless of how the array was declared.
To answer your updated question, for C/Fortran interoperability, use the ISO_C_BINDING feature which is nowadays widely available. This provides a standardized way to pass information between C and Fortran.
如果 Fortran 中常规数组的虚拟参数声明为 A(:)(或具有更多维度),则传递 SHAPE,而不是特定的索引范围。因此该过程将默认为单索引。您可以使用 A(-10:) 或 A(StartIndex:) 过程中的声明来覆盖它,其中 StartIndex 是另一个参数。
Fortran 指针确实包含索引范围,但传递机制将取决于编译器。将其与 C 接口的代码可能是 OS &依赖于编译器。正如已经建议的,我将使用常规数组和 ISO C 绑定。它比弄清楚编译器传递机制以及标准和可移植的旧方法要容易得多。如果您有大量的现有 Fortran 代码,则可以编写一个“粘合”Fortran 过程,在常规 Fortran 变量声明和 ISO C 绑定名称之间进行映射。虽然它们的类型在形式上具有不同的名称,但实际上,如果您选择正确的 ISO C 类型,它们将是相同的。 ISO C 绑定现已推出多年 - 您可以升级问题目标平台上的编译器吗?如果没有,我会使用常规 Fortran 数组,并在 C 端使用零索引,或者显式传递所需索引作为参数。
其他 Stack Overflow 问题上有 ISO C 绑定用法的示例。
如果声明过程的接口是显式的,以便调用者中的编译器知道它。最简单的方法是将过程放置在模块中并在调用者中“使用”该模块。拥有显式接口有助于避免错误,因为编译器可以检查调用者和被调用者参数之间的一致性。它有点像 C 头文件,只是更简单。
If the dummy argument for a regular array in Fortran is declared A(:) (or with more dimensions), the SHAPE is passed, not the specific index range. So the procedure will default to one-indexing. You can override this with a declaration in the procedure of A(-10:), or A(StartIndex:), where StartIndex is another argument.
Fortran pointers do include the index range, but the passing mechanism will be compiler dependent. Code interfacing this to C is likely to be OS & compiler dependent. As already suggested, I'd use a regular array and the ISO C Binding. It is MUCH easier than the old ways of figuring out the compiler passing mechanisms and standard and portable. If you have a large existing Fortran code, you could write a "glue" Fortran procedure that maps between the regular Fortran variable declarations and the ISO C Binding names. While they types will have formally different names, in practice they will be the same if you select the correct ISO C types. The ISO C Binding has been available for many years now -- can you upgrade the compiler on the problem target platform? If not, I'd use a regular Fortran array and either use zero-indexing on the C-side, or explicitly pass as arguments the desired indices.
There are examples of ISO C Binding usage on other Stack Overflow questions.
The interface to a procedure is explicit if it is declared so that it is known to the compiler in the caller. The simplest way it to place the procedures in a module and "use" the module in the caller. Having explicit interfaces helps avoid bugs since the compiler can check consistency between arguments of the caller and callee. It is a little bit like C header files, only easier.