Fortran reinterpret_cast等效

时间:2017-09-29 18:09:42

标签: casting fortran

我在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)的值)?

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。他们(structureunionrecord)是在将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伪参数的地址仅在子例程中有效,除非实际参数是指针或目标。