我在Fortran中编写了一些以结构作为参数的函数,但调用者将数据存储在INTEGER*4(2)
数组中。为了避免两个数据结构之间的复制,我想知道C ++的以下实现 - 比如reinterpret_cast根据规范是否有效:
STRUCTURE /TimeStamp/
INTEGER*4 secondsSinceEpoch
INTEGER*4 nanos
END STRUCTURE
STRUCTURE /reinterpret_cast/
UNION
MAP
INTEGER*4, POINTER :: array(:)
END MAP
MAP
TYPE (TimeStamp), POINTER :: tstamp
END MAP
END UNION
END STRUCTURE
SUBROUTINE set_time(timeArg)
INTEGER*4, TARGET :: timeArg(2)
RECORD /reinterpret_cast/ time
time % array => timeArg
time % tstamp % secondsSinceEpoch = 12
time % tstamp % nanos = 0
END
set_time
方法的此实施是否有效(例如,设置timeArg(1)
和timeArg(2)
的值)?
答案 0 :(得分:2)
您正在寻找的是F90标准功能TRANSFER。它解释操作数的位表示,就好像它是另一个变量的相同类型(“模具”)。因此,这个:
USE ISO_FORTRAN_ENV ! For the REALnn and INTnn constants
REAL(REAL32) r
INTEGER(INT32) i
r = 1.0
i = TRANSFER(r, i) ! The second "i" here is unevaluated, just gives the type
等同于:
float r = 1.0;
int32_t i;
i = *reinterpret_cast<int*>(&f);
请注意,REALnn和INTnn常量来自Fortran 2008,因此您的编译器可能没有它们。我只是用它们作为例子来确保类型是兼容的,因为就像在C中一样,标准并没有准确地说出“默认实际”或“默认整数”有多大。
作为一个例子,我经常在Matlab中创建基于Fortran的MEX函数时使用此函数,因为与Fortran的Matlab接口基于F77并且不允许使用指向Matlab内存的指针直接,不像C接口。我使用TRANSFER函数和ISO_C_BINDING模块(F2003)来转换“整数”(实际上是一个C指针)Matlab给了我一个Fortran类型C_PTR,一个Fortran指针。像这样:
USE ISO_C_BINDING ! For C_PTR and related functions
INTEGER(INT32), POINTER :: arrayPtr(:)
mwSize n ! This is a type defined in the Matlab-Fortran interface
mwPointer myMatlabArray = ... ! So is this
TYPE(C_PTR) cPtrToData
! Cast the returned C pointer to the data (Matlab interface returns an integer type)
cPtrToData = TRANSFER(mxGetData(myMatlabArray), cPtrToData)
! Since Fortran arrays/pointers have size information, get the length
n = mxGetNumberOfElements(myMatlabArray)
CALL C_F_PTR(cPtrToData, arrayPtr, [n]) ! Associate the Fortran ptr
array(3:7) = ... ! Do whatever, no need to copy
这与C版本大致相同:
mxArray* myMatlabArray = ...; //
mwSize n = mxGetNumberOfElements(myMatlabArray);
int* arrayPtr = (int*)mxGetData(myMatlabArray);
array[3] = ... // Do whatever, no need to copy
因此,在这两种情况下,可以使用Matlab类型为int32的Matlab数组调用这些MEX函数。
答案 1 :(得分:2)
不,您的功能无法保证按Fortran标准运行,许多编译器将完全拒绝语法。我不确定DEC structure
中是否允许使用Fortran指针,如果是,是否可以union
。他们(structure
和union
和record
)是在将Fortran指针放入标准之前设计的,并且强烈建议不要使用新代码,但英特尔很可能允许Fortran指针允许它们
更容易(至少对我来说)方式是使用Fortran标准type(c_ptr)
,它基本上是C void *
指针。
SUBROUTINE set_time(timeArg)
USE, INTRINSIC :: ISO_C_BINDING
INTEGER(c_int_32), TARGET :: timeArg(2)
type(TimeStamp), POINTER :: tstamp
CALL c_f_pointer(c_loc(timeArg), tstamp)
tstamp % secondsSinceEpoch = 12
tstamp % nanos = 0
END
我还更改了INTEGER*4
,因为它也不符合标准,并且不能保证C互操作。
请注意target
伪参数的地址仅在子例程中有效,除非实际参数是指针或目标。