Fortran标准不断发展,并且随着新的内在变量的引入,编译器会在一段时间之后选择它们。一个例子是变量C_PTRDIFF_T
。
为了使我的代码也可以与旧的编译器兼容,我想定义内部变量,如果它们尚未由编译器本身定义,例如,
program test
USE ISO_C_BINDING
Integer, Parameter :: C_PTRDIFF_T = 12
end program
如何在编译器之间实现这种可移植性?
答案 0 :(得分:2)
尝试编译并运行类似于:
的内容USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTRDIFF_T
IF (C_PTRDIFF_T >= 0) THEN
PRINT "('Ok')"
ELSE
PRINT "('Not ok')"
END IF
END
如果编译成功,编译器会知道支持C_PTRDIFF_T的标准。
如果运行程序然后打印Ok(所以C_PTRDIFF_T常量的值是非负的),处理器还支持一个可与相关C类型互操作的整数。
根据此测试,您可以根据需要正确配置您的程序,也许可以为模块选择略有不同的源代码,该模块可以提供ISO_C_BINDING的独立定义或转发C_PTRDIFF_T。
后期标准将新实体添加到内部模块的能力是有时建议在内部模块的USE语句中始终使用ONLY子句的编程样式的原因。
(注意C_PTRDIFF_T是内部模块中的常量,它不是变量也不是内在的。)
答案 1 :(得分:0)
您可以在一个过程中实现此目标,因为USE关联胜过主机关联:
module goodstuf
implicit none
interface f
module procedure f4, f8
end interface f
contains
function f4(x)
integer(4) f4
integer(4), intent(in) :: x
f4 = x**2+1
end function f4
function f8(x)
integer(8) f8
integer(8), intent(in) :: x
f8 = x**3-1
end function f8
end module goodstuf
module user5713492_C_BINDING
implicit none
! integer, parameter :: C_PTRDIFF_T = 8
end module user5713492_C_BINDING
module anymod
use goodstuf
implicit none
integer, parameter :: C_PTRDIFF_T = 4
contains
subroutine sub
use user5713492_C_BINDING
integer(C_PTRDIFF_T) x
x = 7
write(*,*) f(x)
end subroutine sub
end module anymod
program main
use anymod
implicit none
call sub
end program main
在模块50
中注释掉C_PTRDIFF_T
的定义时,将打印出user5713492_C_BINDING
,而在模块342
中,则将其注释掉。但是我希望做的是定义一个命名常量,该常量在定义1
时具有值C_PTRDIFF_T
,而在没有0
时具有值。我可以通过使用隐式类型的test
,STORAGE_SIZE
和BIT_SIZE
内在函数为命名常量DIM
实现此功能,假设默认整数KIND
不是INT8
。但是,在未定义C_PTRDIFF_T
的情况下进行压缩似乎需要某种编译器错误。我使用gfortran进行了尝试,并发现了两个错误,最后一个错误使该错误得以解决,将FSOURCE=
自变量压缩为MERGE
内部变量。不幸的是,它不适用于ifort。
module goodstuf
implicit none
interface f
module procedure f4, f8
end interface f
contains
function f4(x)
integer(4) f4
integer(4), intent(in) :: x
f4 = x**2+1
end function f4
function f8(x)
integer(8) f8
integer(8), intent(in) :: x
f8 = x**3-1
end function f8
end module goodstuf
module user5713492_C_BINDING
implicit none
! integer, parameter :: C_PTRDIFF_T = 8
end module user5713492_C_BINDING
module filter
use user5713492_C_BINDING
use ISO_FORTRAN_ENV, only: INT8
implicit integer(INT8) (C)
integer, parameter :: PTRDIFF_size = storage_size(C_PTRDIFF_T)
integer, parameter :: test = dim(1,(PTRDIFF_size-bit_size(1))**2)
integer, parameter :: MY_PTRDIFF_T = 4
! First test: try to squash PAD= argument to RESHAPE
! integer, parameter :: array1(test) = reshape([integer(INT8)::],[test],pad=[C_PTRDIFF_T])
! integer, parameter :: array2(1) = reshape(array1,[1],pad=[MY_PTRDIFF_T])
! Second test: try to squash assignment to zero-length array
! integer, parameter :: array1(test) = C_PTRDIFF_T
! integer, parameter :: array2(1) = reshape(array1,[1],pad=[MY_PTRDIFF_T])
! Third test: try to squash zero-length structure constructor
! Fails with gfortran with C_PTRDIFF_T defined. Bug?
! type T
! integer array(test)
! end type T
! type(T), parameter :: T1 = T(C_PTRDIFF_T)
! integer, parameter :: array2(1) = reshape(T1%array,[1],pad=[MY_PTRDIFF_T])
! Fourth test: try to squash BOUNDARY= argument to EOSHIFT
! gfortan gives misleading error message with C_PTRDIFF_T undefined.
! integer, parameter :: array2(1) = eoshift([integer(KIND(C_PTRDIFF_T))::MY_PTRDIFF_T],1,boundary=C_PTRDIFF_T)
! Fifth test: try to squash FSOURCE= argument to MERGE
!!! WORKS WITH gfortran!!!
integer, parameter :: array2(1) = merge([integer(KIND(C_PTRDIFF_T))::MY_PTRDIFF_T],C_PTRDIFF_T,test==0)
integer, parameter :: OK_PTRDIFF_T = array2(1)
end module filter
program main
use goodstuf
use filter
implicit none
integer(OK_PTRDIFF_T) x
x = 7
write(*,*) f(x)
end program main