The Fortran standard evolves and as new intrinsic variables are introduced, compilers pick those up after a while. One example is the variable C_PTRDIFF_T.
To make my code compilable with older compilers as well, I'd like to define intrinsic variables if they are not already defined by the compiler itself, e.g,
program test
USE ISO_C_BINDING
Integer, Parameter :: C_PTRDIFF_T = 12
end program
How can I make this portable across compilers?
Try and compile and run something akin to:
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTRDIFF_T
IF (C_PTRDIFF_T >= 0) THEN
PRINT "('Ok')"
ELSE
PRINT "('Not ok')"
END IF
END
If compilation suceeds, the compiler is aware of the standard that supports C_PTRDIFF_T.
If running the program then prints Ok (so the value of C_PTRDIFF_T constant is non-negative), the processor also supports an integer that is interoperable with the relevant C type.
Based on this test you can then configure your program proper as appropriate, perhaps by selecting slightly different source code for a module that either provides a stand-alone definition of or forwards C_PTRDIFF_T from ISO_C_BINDING.
The ability for later standards to add new entities to the intrinsic modules is why a programming style that always uses an ONLY clause on USE statements for intrinsic modules is sometimes recommended.
(Note C_PTRDIFF_T is a constant in an intrinsic module, it is not a variable nor intrinsic.)
You can achieve this within a procedure because USE association trumps host association:
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
This prints out 50 when the definition of C_PTRDIFF_T is commented out in module user5713492_C_BINDING and 342 when it is in effect. But what I was hoping to do was to define a named constant that had the value 1 when C_PTRDIFF_T was define and 0 when not. I could achieve this for the named constant test via the STORAGE_SIZE, BIT_SIZE, and DIM intrinsics using implicit typing assuming the KIND of a default integer was not INT8. But then to squash C_PTRDIFF_T when it's not defined seems to require a compiler bug of some sort. I tried this with gfortran and turned up a couple of bugs, and finally one that allowed this to work, squashing the FSOURCE= argument to the MERGE intrinsic. It didn't work with ifort, unfortunately.
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
Related
I am working on a Fortran code. And I have to deal with many different type of output file. So to manage all of them, I use type objects.
Until now, I have compiled my code with gfortran on linux and windows (and ifort on linux) ; and it works as expected.
Because, I want in a close future to integrate GPU parallel computing to my code with OpenACC, I have to be able to compile it with pgfortran (the PGI compiler for Fortran).
Here arrives my problem, the compilation (with pgfortran 18-4-0 on windows) returns me no warning, but at the execute the code crashes with a strange error: [Exit 3221225477] test.exe.
Therefore, I tried to isolate the problem, in order to solve it. I finally get the following MWE:
MODULE VTK_IO
implicit none
type, abstract :: FormatVTK
contains
procedure(VTK_open_file),nopass, deferred :: open_file_VTK
procedure(VTK_close_file),nopass, deferred :: close_file_VTK
end type FormatVTK
type, extends(FormatVTK) :: FormatAscii
contains
procedure, nopass :: open_file_VTK => open_file_ascii
procedure, nopass :: close_file_VTK => close_file_ascii
end type FormatAscii
type, public :: VTKfileHandler
integer :: unit
class(FormatVTK), allocatable :: type
end type VTKfileHandler
abstract interface
subroutine VTK_open_file( fd )
import VTKfileHandler
class(VTKfileHandler), intent(inout) :: fd
end subroutine
subroutine VTK_close_file(fd)
import VTKfileHandler
class(VTKfileHandler), intent(in) :: fd
end subroutine
end interface
contains
subroutine open_file_ascii( fd )
implicit none
class(VTKfileHandler), intent(inout) :: fd
character(len=80) :: f
!-------------------------------------------------------------------------
write(unit=*, fmt=*) 'open_file_ascii: start'
! stop 6969
f='test_file.txt'
open(newunit = fd%unit, &
file = trim(adjustl(f)), &
form = 'FORMATTED', & ! FORMATTED
access = 'STREAM', & ! SEQUENTIAL
action = 'WRITE', &
status = 'REPLACE')
write(unit=fd%unit,fmt='(100A)') "# vtk DataFile Version "
write(unit=*, fmt=*) 'open_file_ascii: end'
end subroutine open_file_ascii
subroutine close_file_ascii(fd)
implicit none
class(VTKfileHandler), intent(in) :: fd
!-------------------------------------------------------------------------
close(unit=fd%unit)
write(unit=*, fmt=*) 'close_file_ascii: done'
end subroutine close_file_ascii
end module vtk_IO
PROGRAM Test_open
USE VTK_IO
IMPLICIT NONE
type :: OutputFile
class (VTKfileHandler), allocatable :: VTKfile
end type OutputFile
type (OutputFile) :: OutsFiles
!----------------------------------------------------------------------------
print*, 'START: Test_open'
Print*,'initialise_outputs: start'
allocate(VTKfileHandler :: OutsFiles%VTKfile )
allocate(FormatAscii :: OutsFiles%VTKfile%type)
Print*,'initialise_outputs: end'
call OutsFiles%VTKfile%type%open_file_VTK(OutsFiles%VTKfile)
call OutsFiles%VTKfile%type%close_file_VTK(OutsFiles%VTKfile)
print*, 'END: Test_open'
END PROGRAM Test_open
It seems like the type-bound procedure open_file_VTK is not targetting the procedure open_file_ascii. I think that the compiler get lost with the type-bounded procedure. For example, if I remove the OutsFiles and use directly a VTKfile in the main, it works. But, of course, I need this embedding type OutputFile, in my big code ; otherwise it would be too easy.
So is it a bug from the compiler ? Or can I do something to solve this problem ?
I want to combine C++ and Fortran together. My Fortran code will use a C++ function and C++ function changes variables of Fortran and sends them back. The C++ function is built with other C++ codes, e.g. the C++ function will use some sub-function in other .cpp file. I make the Fortran code with ifort and I added that C++ function as one object file, test.o in my Fortran makefile. I also put every needed C++ .o file(support test.o) in makefile. It shows the error
#6633, "The type of the actual argument differs from the type of the dummy argument".
Here is the code.
Fortran code
use, intrinsic :: ISO_C_BINDING, only: C_INT, C_DOUBLE
implicit double precision(a-h,o-z),integer(i-n)
Interface
integer (C_INT) function SolveBIE_(x, y, aa, m) BIND(C, NAME='SolveBIE_')
use, intrinsic :: ISO_C_BINDING
implicit none
type (C_PTR), value :: x
type (C_PTR), value :: y
type (C_PTR), value :: aa
integer (C_INT), value :: m
end function SolveBIE_
end Interface
integer (C_INT) :: m
real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: x
real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: y
real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: aa
ALLOCATE(x(0:MAXLEN,MAXINTERFACES))
ALLOCATE(y(0:MAXLEN,MAXINTERFACES))
ALLOCATE(aa(0:MAXLEN,MAXINTERFACES))
My Fortran code run
mm = SolveBIE_(x(1,1),y(1,1),aa(1,1),m)
Using the C++ code and where the error is from, on x, y, aa
I use x(1,1) instead of x, because if using x, then there is another error
#6634,"the shape matching rules of actual arguments and dummy arguments have been violated"`
I don't understand why it should be x(1,1). Why is this working, not x?
My C++ code
#ifdef __cplusplus
extern "C" {
#endif
int solveBIE_(double *ini_bdry_x, double *ini_bdry_y, double *ini_bdry_um, int *fM)
{
double(*bdry_node)[2] = new double[M1][2];
for (int k = 0; k < M; k++) {
bdry_node[k+1][0] = ini_bdry_x[k+1];
bdry_node[k+1][1] = ini_bdry_y[k+1];
bdry_theta[k+1] = Atan(ini_bdry_x[k+1], ini_bdry_y[k+1]);}
... some functions in other .cpp file
The way your interface is written, you have to construct a C_PTR to array x and pass that as the first argument:
use, intrinsic :: ISO_C_BINDING, only: C_INT, C_DOUBLE, C_PTR, C_LOC
! ...
type(C_PTR) PTRx
! ...
PTRx = C_LOC(x(LBOUND(x,1),LBOUND(x,2)))
! ...
mm = solveBIE_(PTRx, PTRy, PTRaa, m)
As shown above, you would have to fix the next two arguments as well. But you need to rewrite the interface for argument fM because as matters stand, Fortran will pass an integer by value whereas C++ is expecting a pointer. Given that, I would rewrite the interface completely, using the names given for the arguments in the C++ function and passing everything by reference. Names for dummy arguments are potentially visible in Fortran, so it's useful for them to be meaningful. In the following I assume that fM points to a scalar in the callee:
Interface
function SolveBIE_(ini_bdry_x, ini_bdry_y, ini_bdry_um, fM) &
BIND(C, NAME='SolveBIE_')
import
implicit none
integer(C_INT) SolveBIE_
real(C_DOUBLE) :: ini_bdry_x(*)
real(C_DOUBLE) :: ini_bdry_y(*)
real(C_DOUBLE) :: ini_bdry_um(*)
integer (C_INT) :: fM
end function SolveBIE_
end Interface
Then later on you can invoke it more or less normally as
mm = SolveBIE_(x,y,aa,m)
Note that x(1,1) was wrong because LBOUND(x,1) = 0, not 1!
I am using Fortran 90 and the Intel compiler.
I am very confused using a function in a subroutine. My code is (I deleted everything unimportant):
program test
INTEGER :: seed=5
REAL :: nor_ran_number1, nor_ran_number2
CALL Box_Muller_transform(seed,nor_ran_number1,nor_ran_number2)
end program test
double precision function grnd(SEED)
grnd=5
return
end
SUBROUTINE Box_Muller_transform (seed,nor_ran_number1,nor_ran_number2)
implicit none
INTEGER, INTENT(in) :: seed
REAL, INTENT(out) :: nor_ran_number1, nor_ran_number2
nor_ran_number1 = grnd(seed)
nor_ran_number2 = grnd(seed)
end SUBROUTINE Box_Muller_transform
The compiler returns:
error #6404: This name does not have a type, and must have an explicit
type. [GRND]
nor_ran_number1 = grnd(seed)
------------------^
I found this and understand that the function "grad" is not visible inside "Box_Muller_transform". However then I would expect the following code to produce the same error:
program test
INTEGER ::a=5, b
call sub(a,b)
write(*,*) b
end program
SUBROUTINE sub(a,b)
INTEGER, INTENT(in) ::a
INTEGER, INTENT(out) ::b
b = fun(a)
end subroutine sub
function fun(a)
INTEGER :: fun
INTEGER :: a
fun = a*a
end function fun
But this is working.
I would be very happy if someone could point out the difference and explain the simplest way to solve this problem.
Functions must have their return value defined. Since you are using implicit none in your first example, the type of the return value of grnd must be defined explicitly:
SUBROUTINE Box_Muller_transform (seed,nor_ran_number1,nor_ran_number2)
implicit none
INTEGER, INTENT(in) :: seed
REAL, INTENT(out) :: nor_ran_number1, nor_ran_number2
double precision :: grnd
nor_ran_number1 = grnd(seed)
nor_ran_number2 = grnd(seed)
end SUBROUTINE Box_Muller_transform
In the second example, you have not specified implicit none in sub, therefore fun is assumed to be of (implicit) type real. The compiler seems to silently cast this to integer.
Trying to learn Fortran for a project. In a very simple program I am getting invalid character error.
program foo
implicit none
integer :: n_samp
integer :: samp_len
integer :: x_len
integer :: y_len
n_samp=2
samp_len=2
y_len=11
x_len=2
real(8),dimension(n_samp,samp_len,y_len,x_len)=Yvec
end program foo
error generated by GFORTRAN
t.f90:11.12:
real(8), dimension(n_samp,samp_len,y_len,x_len)=Yvec
1
Error: Invalid character in name at (1)
What is the cause of this error?
The correct syntax is
real(8), dimension(n_samp,samp_len,y_len,x_len) :: Yvec
The :: is obligatory when specifying any attributes (as the dimension in your case).
As #AlexanderVoigt points out, all variable declaration must be placed in the declaration part of the code, i.e., at the beginning.
I do not recommend using real(8) because that is not well defined, the 8 can mean anything, it is an index to a table of kinds and different compilers can have something different at place 8 in that table. See Fortran 90 kind parameter
That's simple: You are not allowed to have declarations in the main body (that is after some instructions)! Instead, you should use parameters:
program foo
implicit none
integer,parameter :: n_samp=2
integer,parameter :: samp_len=2
integer,parameter :: x_len=11
integer,parameter :: y_len=2
real(8),dimension(n_samp,samp_len,y_len,x_len) :: Yvec ! Add. typo here
end program foo
I try the following codes, and find the OPTIONAL keyword does not work. The compile is ok, but the runtime error will prompt.
I know usually the INTERFACE should be used in the module to provide enough information for the routines. I also try that, but failed to finish the compile no matter where I put the INTERFACE.
I have read some codes which use OPTIONAL in the TYPE declaration. https://www.pgroup.com/lit/articles/insider/v3n1a3.htm
Now I am using intel visual fortran, so is there any difference?
module testA_m
implicit none
type :: onion_c
contains
procedure :: testA
end type
contains
subroutine testA(this, a,b)
implicit none
class(onion_c) :: this
real*8 :: a
real*8, optional :: b
write(*,*) a,b
end subroutine
end module
program main
call testIt()
end program
subroutine testIt()
use testA_m
implicit none
type(onion_c) :: onion
real*8 :: c1
real*8 :: c2
c1 = 1.0d0
c2 = 2.0d0
call onion.testA(c1)
end subroutine
Well, you are trying to print b, which is not passed to the subroutine. Hence the access violation.
You should check for b first:
subroutine testA(this, a,b)
implicit none
class(onion_c) :: this
real*8 :: a
real*8, optional :: b
if ( present(b) ) then
write(*,*) a,b
else
write(*,*) a
endif
end subroutine
Maybe I need another variable for the real operation. Like the following.
I am still looking forward the better solution to use b directly.
subroutine testA(this, a,b)
implicit none
class(onion_c) :: this
real*8 :: a
real*8, optional :: b
real*8 :: bUsed
if ( present(b) ) then
bUsed = b
write(*,*) a,bUsed
else
bUsed = 2.00d0
write(*,*) a,bUsed
endif
end subroutine
Because Fortran does not support a program like
subroutine testA( this, a, b=10.0d0 )
I usually define a macro like the following in a common header file
#define _optval_(x,xopt,default) x = default; if (present(xopt)) x = xopt
and then use it at the top of a subroutine like
subroutine testA(this, a,b_)
class(onion_c) :: this
real*8 :: a
real*8, optional :: b_
real*8 b
_optval_( b, b_, 10.0d0 ) !! use only b from here on
Although this is not essentially different from writing several IF constructs, I feel it is a bit more convenient (at least for simple variables) because no need to worry about whether b is optional or not in the subsequent code. (But frankly, I hope Fortran2020 or so will support a syntax like the first example...)