I have a simple question regarding derived types and allocated arrays.
Suppose we have defined the type
type demo_type
real(kind=8),allocatable :: a(:)
end type demo_type
and the function
function demo_fill(n) result(b)
integer, intent(in) :: n
real(kind=8) :: b(n)
b = 1.d0
end function demo_fill
Is it correct to write in the main program
type(demo_type) :: DT
DT%a = demo_fill(3)
Or is it necessary to first allocate DT%a to prevent accidentally overwriting other variables in memory?
type(demo_type) :: DT
allocate(DT%a(3))
DT%a = demo_fill(3)
They both compile, but I am wondering which is the correct way. Thanks!
In Fortran 2003 any allocatable array can be allocated automatically on assignment.
In your case
DT%a = demo_fill(3)
causes DT%a to be automatically allocated to the shape of the right hand side, which is the result of the function, if it has not been allocated to this shape previously.
This behavior is standard, but some compilers do not enable it by default, notably the Intel Fortran. You must use special compiler flags to enable it (-standard-semantics, -assume realloc_lhs)
As a side note, kind=8 does not mean 8-byte reals on all compilers, and this usage is frowned upon (see https://stackoverflow.com/a/856243/721644).
Related
I am trying to call some Fortran code from C but I didn't find the proper way of passing a C char array.
SUBROUTINE My_F_Code (c_message) BIND(C, NAME='my_f_code')
USE ISO_C_BINDING
IMPLICIT NONE
CHARACTER*(C_CHAR) c_message
CHARACTER*(256) f_message
CALL C_F_POINTER( C_LOC(c_message), f_message)
WRITE(*,*) f_message,LEN(f_message)
END
The BIND(C) force the parameter c_message to be size 1. How can I access to other elements of the c_message string?
Compiler : GCC 4.8.2
I am trying to call some Fortran77 code from C but I didn't find the proper way of passing a C char array.
All Fortran 77 implementations I've ever used have afforded implementation-specific mechanisms for interoperation with C. Generally these involve the C side knowing the name-mangling and argument-passing conventions employed by the Fortran compiler, and using them at the interface. The GCC system's conventions are not that hard to use.
You seem to be interested in the Fortran/C interop facility introduced in Fortran 2003, however. Supposing that your Fortran 77 code also conforms with Fortran 2003 (or can be made to do so), it should be possible to write an interoperable wrapper in Fortran 2003. Be aware, however, that the C interop facility does not provide (directly) for interoperability of Fortran variables or subprogram parameters of type character with length greater than 1 or kind different from c_char. On the other hand, keep also in mind that the length of a Fortran character object is not the same thing as the dimension(s) of a character array.
You have a couple of interoperable alternatives for providing a C-facing interface by which to accept a C char array. Perhaps the clearest one would be to accept a Fortran assumed-size character array:
SUBROUTINE My_F_Code (c_message) BIND(C, NAME='my_f_code')
USE ISO_C_BINDING
IMPLICIT NONE
CHARACTER(kind=C_CHAR), dimension(*), intent(in) :: c_message
! ...
END
The most likely alternative is to accept C's array pointer directly:
SUBROUTINE My_F_Code (c_message) BIND(C, NAME='my_f_code')
USE ISO_C_BINDING
IMPLICIT NONE
type(C_PTR), value :: c_message
! ...
END
The latter is necessary if the C-side array pointer might be null. Both require an explicit length to be passed as well if the array cannot be relied upon to be null terminated.
In any event, if you ultimately want a Fortran character variable having length greater than 1 (as opposed to an array having dimension greater than 1), then the interoperable interfaces can't provide that directly -- such types are not among those to which the C interop provisions are applicable. Unless you can rely on the default character kind to be c_char, you'll need to couple them with copy-in(/ copy-out) in order to convert the characters between kinds. With the former interface, it should be obvious how you could copy the array to a Fortran scalar character having length greater than 1. For the pointer variant, it might be useful to use a conversion function something like this:
subroutine C_string_ptr_to_F_string(C_string, F_string)
use ISO_C_BINDING
type(C_PTR), intent(in) :: C_string
character(len=*), intent(out) :: F_string
character(len=1, kind=C_CHAR), dimension(:), pointer :: p_chars
integer :: i
if (.not. C_associated(C_string)) then
F_string = ' '
else
call C_F_pointer(C_string, p_chars, [huge(0)])
do i = 1, len(F_string)
if (p_chars(i) == C_NULL_CHAR) exit
F_string(i:i) = p_chars(i)
end do
if (i <= len(F_string)) F_string(i:) = ' '
end if
end subroutine
(Derived from the Fortran Wiki's C_interface_module's C_F_string_ptr subroutine)
On the other hand, if you can (or anyway do) rely on the default character kind to be c_char then you have an additional alternative. You can usefully cause a character array such as the parameter in the first example to be associated with a scalar character object of default kind and length greater than one. In particular, if a dummy argument of the wrapped function is a scalar character with assumed length, or with fixed length not exceeding the number of array elements, then you can rely on argument association to associate it with the character array in the wrapper. In other words, in that case you can just pass the array as the actual argument.
SUBROUTINE FCODE(STR, N)
CHARACTER*(*) STR
INTEGER N
WRITE(*,*), STR, N
END
void foo(char *str)
{
int N = 10;
printf("Calling fortran\n");
fcode_(str, &N, strlen(str));
}
You need to pass sgtring length as a hidden parameter.
See my article here
http://www.malcolmmclean.site11.com/www/MpiTutorial/CandFortran77.html
I'm trying to decide which one of these two options would be the best:
subroutine sqtrace( Msize, Matrix, Value )
integer, intent(in) :: Msize
real*8, intent(in) :: Matrix(Msize, Msize)
real*8, intent(out) :: Value
[instructions...]
end subroutine sqtrace
VS
subroutine sqtrace( Matrix, Value )
real*8, intent(in) :: Matrix(:,:)
real*8, intent(out) :: Value
if ( size(Matrix,1) /= size(Matrix,2) ) then
[error case instructions]
end if
[instructions...]
end subroutine sqtrace
I understand that when you compile with warnings, the first case should automatically check at compile time if calls to sqtrace comply with the size indicated. However, I don't know if the compiler can perform those checks when the given arguments are allocatable, for example (more so if such allocation depends on other things that are determined at runtime). The second one requires an explicit interface and has more code (the checks), but would seem to catch more errors.
Which are the advantages/disadvantages of using each and in which cases should one go with one over the other?
First, some terminology. Consider the dummy arguments declared as
real :: a(n) ! An explicit shape array
real :: b(:) ! An assumed shape array
real, allocatable :: c(:) ! A deferred shape array (allocatable)
real, pointer :: d(:) ! A deferred shape array (pointer)
real :: e(*) ! An assumed size array
real :: f(..) ! An assumed rank array/scalar
I won't answer in terms of which is better in a given situation, but will simply detail some of the important characteristics leaving choice, where there is one, to the programmer. Crudely (and incorrectly), many view explicit shape arrays as "Fortran 77" and assumed and deferred shape arrays as "Fortran 90+".
Assumed size and assumed rank arguments are beyond the scope of this question and answer.
Shape:
the shape of an explicit shape array follows its declaration;
the shape of an assumed shape array dummy argument is that of the actual argument;
the shape of a deferred shape dummy argument may be undefined, becoming defined in the procedure, or that of the actual argument.
Contiguousness:
an explicit shape array is simply contiguous;
an assumed shape array dummy argument's contiguousness relates to that of the associated actual argument;
a deferred shape dummy argument may be that of the actual argument, or depending on the procedure's execution.
Restrictions on actual argument:
an actual argument associated with an explicit shape array must have at least as many elements as the dummy argument;
an actual argument associated with an assumed shape array must not itself be assumed size;
an actual argument associated with an assumed or deferred shape array must be of the same rank as the dummy argument.
Interfaces in the calling scope:
if a dummy argument is of assumed or deferred shape, the referencing scope must have accessible an explicit interface for the procedure.
Consider real a(6). This may be an actual argument to the dummies
real b(3)
real c(2,3)
real d(:) ! With an explicit interface available
a(1::2) may be associated with b but as b is contiguous copy-in/copy-out will be involved. Copy-in/copy-out needn't be involved when associated with d, but it may be.
There are plenty of other aspects, but hopefully this is an initial high-level introduction.
This question already has answers here:
Automatic array allocation upon assignment in Fortran
(2 answers)
Closed 4 years ago.
In Fortran, if I use an allocatable array that is not allocated in an array assignment, I expect that there will appear some runtime errors.
But it turns out that the allocatable array got allocated during the assignment. This seems to be a dangerous design. Could someone explain the reason for this design? An example code is as follows:
module yj_mod
real,dimension(:,:),allocatable :: den_i_right
end module yj_mod
program main
call p()
end program main
subroutine p()
use yj_mod,only : den_i_right
implicit none
real :: a(3,4)
a=3.0
den_i_right=a
write(*,*) size(den_i_right,1), size(den_i_right,2)
end subroutine p
I compiled the above code with gfortran. Running the code indicates den_i_right becomes an array of the same shape as a
It is informally called (..... wait for it .....) (re-)allocation on assignment. The specific language from the Fortran 2003 standard using variable=expr
"If variable is an allocated allocatable variable, it is deallocated if expr is an array of different shape or any of the corresponding length type parameter values of variable and expr differ. If variable is or becomes an unallocated allocatable variable, then it is allocated with each deferred type parameter equal to the corresponding type parameters of expr, with the shape of expr, and with each lower bound equal to the corresponding element of LBOUND(expr)."
I'm trying to decide which one of these two options would be the best:
subroutine sqtrace( Msize, Matrix, Value )
integer, intent(in) :: Msize
real*8, intent(in) :: Matrix(Msize, Msize)
real*8, intent(out) :: Value
[instructions...]
end subroutine sqtrace
VS
subroutine sqtrace( Matrix, Value )
real*8, intent(in) :: Matrix(:,:)
real*8, intent(out) :: Value
if ( size(Matrix,1) /= size(Matrix,2) ) then
[error case instructions]
end if
[instructions...]
end subroutine sqtrace
I understand that when you compile with warnings, the first case should automatically check at compile time if calls to sqtrace comply with the size indicated. However, I don't know if the compiler can perform those checks when the given arguments are allocatable, for example (more so if such allocation depends on other things that are determined at runtime). The second one requires an explicit interface and has more code (the checks), but would seem to catch more errors.
Which are the advantages/disadvantages of using each and in which cases should one go with one over the other?
First, some terminology. Consider the dummy arguments declared as
real :: a(n) ! An explicit shape array
real :: b(:) ! An assumed shape array
real, allocatable :: c(:) ! A deferred shape array (allocatable)
real, pointer :: d(:) ! A deferred shape array (pointer)
real :: e(*) ! An assumed size array
real :: f(..) ! An assumed rank array/scalar
I won't answer in terms of which is better in a given situation, but will simply detail some of the important characteristics leaving choice, where there is one, to the programmer. Crudely (and incorrectly), many view explicit shape arrays as "Fortran 77" and assumed and deferred shape arrays as "Fortran 90+".
Assumed size and assumed rank arguments are beyond the scope of this question and answer.
Shape:
the shape of an explicit shape array follows its declaration;
the shape of an assumed shape array dummy argument is that of the actual argument;
the shape of a deferred shape dummy argument may be undefined, becoming defined in the procedure, or that of the actual argument.
Contiguousness:
an explicit shape array is simply contiguous;
an assumed shape array dummy argument's contiguousness relates to that of the associated actual argument;
a deferred shape dummy argument may be that of the actual argument, or depending on the procedure's execution.
Restrictions on actual argument:
an actual argument associated with an explicit shape array must have at least as many elements as the dummy argument;
an actual argument associated with an assumed shape array must not itself be assumed size;
an actual argument associated with an assumed or deferred shape array must be of the same rank as the dummy argument.
Interfaces in the calling scope:
if a dummy argument is of assumed or deferred shape, the referencing scope must have accessible an explicit interface for the procedure.
Consider real a(6). This may be an actual argument to the dummies
real b(3)
real c(2,3)
real d(:) ! With an explicit interface available
a(1::2) may be associated with b but as b is contiguous copy-in/copy-out will be involved. Copy-in/copy-out needn't be involved when associated with d, but it may be.
There are plenty of other aspects, but hopefully this is an initial high-level introduction.
I have something like
integer a
integer b
b = 0
integer c
a = 0
c = 0
which does not work with the error
"A specification statement cannot appear in the executable section."
However, changing it to
integer a
integer b
integer c
a = 0
b = 0
c = 0
works.
Yes, this is forbidden in Fortran. This is defined in the Fortran 2008 Standard, Cl. 2.3.2 "Statement order":
1 The syntax rules of clause 2.1 specify the statement order within program units and subprograms. These rules
are illustrated in Table 2.1 [...]. Table 2.1 shows the ordering rules for statements and applies to
all program units, subprograms, and interface bodies. Vertical lines delineate varieties of statements that may
be interspersed and horizontal lines delineate varieties of statements that shall not be interspersed. [...] Between USE and CONTAINS statements in a
subprogram, nonexecutable statements generally precede executable statements [...]
(Emphasis mine)
[Slightly off-topic, but related] Please note that while
integer :: a
integer :: b = 0
integer :: c
is allowed, this has the side effect that b gets the save attribute. That is typically not what you want...
The error message is quite clear. Fortran programs and subprograms are divided into two parts. First the specification part where you use modules, define variables, derived types, interfaces... And then the executable part where you put the actual executable statements or control structures.
It is not possible to mix them.
The situation is murkier in f2008, with the BLOCK construct. That construct necessarily lies among the executable statements, but is often there for the sole purpose of adding the capability to place some specification statements after executable statements, as when an assumed length pointer is to be pointed at anonymous memory.
EDIT: Example
module anonymous
use ISO_C_BINDING
implicit none
interface
function malloc(size) bind(C,name='malloc')
import
implicit none
type(C_PTR) malloc
integer(C_SIZE_T), value :: size
end function malloc
subroutine free(ptr) bind(C,name='free')
import
implicit none
type(C_PTR), value :: ptr
end subroutine free
function strlen(str) bind(C,name='strlen')
import
implicit none
type(C_PTR), value :: str
integer(C_SIZE_T) strlen
end function strlen
end interface
contains
function hello()
type(C_PTR) hello
character(LEN=*,KIND=C_CHAR), parameter :: world = &
'Hello, world'//C_NULL_CHAR
character(LEN=len(world),KIND=kind(world)), pointer :: fptr
hello = malloc(len(world,KIND=C_SIZE_T))
call C_F_POINTER(hello,fptr)
fptr = world
end function hello
end module anonymous
program test
use anonymous
implicit none
type(C_PTR) cptr
character(LEN=:,KIND=C_CHAR), pointer :: fptr
integer(C_SIZE_T) hello_len
cptr = hello()
hello_len = strlen(cptr)
BLOCK
character(LEN=hello_len,KIND=C_CHAR), pointer :: temp
call C_F_POINTER(cptr,temp)
fptr => temp
end BLOCK
write(*,'(*(g0))') fptr(1:strlen(cptr))
end program test