I am writing a routine to write strings. Would I need to
check which arguments are present, or can I avoid that?
Subroutine writes &
( &
q1, q2, q3, q4 &
)
Character (len=*), Intent(in) :: q1
Character (len=*), Intent(in), Optional :: q2, q3, q4
Character (len=65) :: s, fmt
fmt = "(x,4(a,x))"
Write (s,fmt) Trim (q1), Trim (q2), Trim (q3), Trim (q4)
Write (*,*) Trim (s)
End Subroutine writes
The rules regarding use of optional dummy arguments are given, clearly, in Fortran 2008 12.5.2.12. If all arguments are present in the call to writes as given in the question then the code is valid and the output would be as expected. However, one can't guarantee this and any non-present argument would make the code invalid.
In particular, passing q2, say, which is not present to TRIM (which doesn't take an optional argument) would be wrong.
There are multiple ways of addressing this problem, but they all involve checking presence. You could follow the arguments in Fortran Fallback code for optional string argument, but below is an alternative as given previously in comments.
It is possible to create an alternative to TRIM which does take an optional argument, returning a zero-length character variable if the argument is not present, and the expected trimmed variable if it is:
subroutine writes(q1, q2, q3, q4)
character(*), intent(in) :: q1, q2, q3, q4
optional q2, q3, q4
character(len=65) s
write(s, '(4(a,:,x))') TRIM(q1), MY_TRIM(q2), MY_TRIM(q3), MY_TRIM(q4)
print*, TRIM(s)
contains
function my_trim(str)
character(*), intent(in), optional :: str
character(:), allocatable :: my_trim
if (PRESENT(str)) then
my_trim = TRIM(str)
else
my_trim = ''
end if
end function
end subroutine
Note, this uses a deferred length character variable for the result, along with automatic allocation (if using ifort remember the necessary compiler flags to correctly compile).
Finally, if you want to ensure that spaces aren't printed between two non-present variables (''//' '//'') extra work will be required. However, the comments indicate that this isn't necessary.
Related
The following function is supposed to convert a C string into a Fortran string and works fine in Release builds, but not in Debug:
! Helper function to generate a Fortran string from a C char pointer
function get_string(c_pointer) result(f_string)
use, intrinsic :: iso_c_binding
implicit none
type(c_ptr), intent(in) :: c_pointer
character(len=:), allocatable :: f_string
integer(c_size_t) :: l_str
character(len=:), pointer :: f_ptr
interface
function c_strlen(str_ptr) bind ( C, name = "strlen" ) result(len)
use, intrinsic :: iso_c_binding
type(c_ptr), value :: str_ptr
integer(kind=c_size_t) :: len
end function c_strlen
end interface
l_str = c_strlen(c_pointer)
call c_f_pointer(c_pointer, f_ptr)
f_string = f_ptr(1:l_str)
end function get_string
However, it seems that c_f_pointer does not tell the Fortran pointer-to-string, f_ptr, the length of the string it is pointing to. In Debug builds, where bounds-checking is active, this results in
Fortran runtime error: Substring out of bounds: upper bound (35) of 'f_ptr' exceeds string length (0)
I'm using gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 and set the standard to 2008.
My question: Is there any way to tell the f_ptr its length without changing the declaration or am I doing something fundamentally the wrong way here?
It seems to run correctly if I specify the shape, but for that f_ptr needs to be an array:
character(len=:), allocatable :: f_string
character(len=1), dimension(:), pointer :: f_ptr
...
call c_f_pointer(c_pointer, f_ptr, [l_str])
However, I cannot find a way to transform that string of rank 1 to the character(len=:), allocatable :: f_string, which apparently has rank 0.
My second question: Is there any way to transfer the f_ptr data into the f_string in this example?
You cannot use c_f_pointer to set the length of the Fortran character pointer (F2018, 18.2.3.3):
FPTR shall be a pointer, shall not have a deferred type parameter [...]
A deferred-length character scalar (or array) therefore cannot be used (the length is a type parameter).
You can indeed use a deferred-shape character array as fptr and then use any number of techniques to copy the elements of that array to the scalar (which is rank-0 as noted).
For example, with substring assignment (after explicitly allocating the deferred-length scalar):
allocate (character(l_str) :: f_string)
do i=1,l_str
f_string(i:i)=fptr(i)
end
Or consider whether you can simply use the character array instead of making a copy to a scalar.
What is the meaning of the following character declaration
character :: c*4
Is it in anyway special for characters or does it apply to all data types?
Is the 4 the same as the length parameter as in
character(len=4) :: c
There are several ways to declare the length of a character entity in a type declaration statement, but explanations of these are spread across several other questions and answers, so let's gather them here. The forms of the question have the same effect.
A character declaration statement may specify the length in the type specifier using the len= form:
character(len=4) :: ... ! Literal constant length
character(len=n) :: ... ! Named constant/variable length
character(len=*) :: ... ! Assumed/implied length
character(len=:) :: ... ! Deferred length
or with the * form:
character*4 :: ... ! Literal constant length
character*(4) :: ... ! Another literal constant length
character*(n) :: ... ! Named constant/variable length
character*(*) :: ... ! Assumed/implied length
character*(:) :: ... ! Deferred length
For the case of a literal constant, the parentheses are optional and not necessary, but are necessary for other cases.
Alternatively, the * form may be used in the entity declaration itself:
character :: a*4, b*(n), c*(*), d*(:)
character(len=2) :: x*4 ! The *4 overrides the len=2
In all cases, 1 is the default length if no value is specified.
If you want to specify length and array shape in this way:
character :: a(5,5)*4
character(len=2), dimension(2) :: b(5,5)*4 ! Shape and length overridden.
The form of specification using * is unique to character lengths (for functions and variables). Even non-character objects with length type parameters cannot use this syntax. However, as Vladimir F notes, there is the similar non-standard form like integer*4.
Finally, the name*(len) form is specific to type declaration statements. It can't be used, for example, in allocation:
character(:), allocatable :: c
allocate(character :: c*4) ! Not allowed as length specification, use instead
allocate(character(len=4) :: c) ! or
allocate(character*4 :: c) ! etc
Yes, they are both strings of the same length. See also Difference between “character*10 :: a” and “character :: a(10)”.
The syntax is completely special for characters and cannot be used for other datatypes. Re-using the syntax for other datatypes like integer*4 might be motivated by the old Hollerith editing, where characters were stored in integer numbers, but is completely non-standard.
In fortran, we can define default arguments. However, if an optional argument is not present, it can also not be set. When using arguments as keyword arguments with default values, this leads to awkward constructs like
PROGRAM PDEFAULT
CALL SUB
CALL SUB(3)
CONTAINS
SUBROUTINE SUB(VAL)
INTEGER, OPTIONAL :: VAL
INTEGER :: AVAL ! short for "actual val"
IF(PRESENT(VAL)) THEN
AVAL = VAL
ELSE
AVAL = -1 ! default value
END IF
WRITE(*,'("AVAL is ", I0)') AVAL
END SUBROUTINE SUB
END PROGRAM PDEFAULT
Personally, I often ran into the problem of accidentially typing VAL instead of AVAL, i.e. the disconnect between the variable name in the interface, and the initialized value used in the code can introduce runtime bugs – let alone that this manner of initialization is rather verbose.
Is there some more elegant way of using optional arguments with a default value?
Example It would feel more natural to write something like
IF(NOT(PRESENT(VAL))) VAL = -1
because it avoids the VAL vs AVAL confusion. But it isn't valid, presumably because Fortran passes arguments by reference and thus if VAL is not present in the CALL statement, no memory is associated with VAL and VAL = -1 would cause a segfault.
You described the situation rather well. There is no other way I am aware off and that is standard conforming. The pattern with a local variable named similarly is what people often use. The other option is to just put if (present()) else everywhere, but that is awkward.
The point is that they are optional arguments, not default arguments. Fortran doesn't have default arguments. The may have been better, but that is not what the committee members have chosen in the 80s when preparing Fortran 90.
While also looking into this, I found out that you can in fact do something like the proposed example using the OPTIONAL and VALUE attributes (at least with gfortran, not sure how different compilers might handle it). E.g.:
PROGRAM PDEFAULT
CALL SUB
CALL SUB(3)
CONTAINS
SUBROUTINE SUB(VAL)
INTEGER, OPTIONAL,VALUE :: VAL
IF(.NOT. PRESENT(VAL)) VAL = -1 ! default value
WRITE(*,'("VAL is ", I0)') VAL
END SUBROUTINE SUB
END PROGRAM PDEFAULT
This was implemented in version 4.9 of gfortran. And here's the relevant explanation in the documentation for argument passing conventions:
For OPTIONAL dummy arguments, an absent argument is denoted by a NULL
pointer, except for scalar dummy arguments of type INTEGER, LOGICAL,
REAL and COMPLEX which have the VALUE attribute. For those, a hidden
Boolean argument (logical(kind=C_bool),value) is used to indicate
whether the argument is present.
I also found this discussion interesting as historical context.
Maybe somebody more knowledgeable might have comments on whether doing this is a bad idea (aside from being compiler dependent), but at least at face value it seems like a nice workaround.
Note that this behavior is not part of the Fortran standard, and depends on the implementation of a given compiler. For example, the example code segfaults when using ifort (version 16.0.2).
The Fortran standard lib (https://github.com/fortran-lang/stdlib) provides a function called optval that is used in stdlib_logger for example:
subroutine add_log_file( self, filename, unit, action, position, status, stat )
...
character(*), intent(in), optional :: action
...
character(16) :: aaction
...
aaction = optval(action, 'write')
...
end subroutine add_log_file
So their way of representing the "actual" value is a prepended a.
IMHO, I like the option with an appended _, since the optional values are visually marked as such in the call signature.
Whilst I certainly wouldn't advocate doing so in most situations (and indeed you can't in some situations), one may sometimes use an interface to provide a single entry point for multiple routines with different required arguments rather than using an optional argument. For example your code could be written like
MODULE subs
implicit none
public :: sub
interface sub
module procedure sub_default
module procedure sub_arg
end interface
contains
SUBROUTINE SUB_arg(VAL)
INTEGER :: VAL
WRITE(*,'("VAL is ", I0)') VAL
END SUBROUTINE SUB_arg
SUBROUTINE SUB_default
integer, parameter :: default = 3
CALL SUB_arg(default)
END SUBROUTINE SUB_default
END MODULE SUBS
PROGRAM test
use subs, only: sub
call sub
call sub(5)
END PROGRAM TEST
Again, I don't recommend this approach, but I thought I should include it anyway as an alternative way of providing something that looks like a default.
Another possibility is to use an associate block which associates the local variable name with a variable of the same name as the optional argument eg.
SUBROUTINE SUB(VAL)
INTEGER, OPTIONAL :: VAL
INTEGER :: AVAL ! short for "actual val"
IF (PRESENT(VAL)) THEN
AVAL = VAL
ELSE
AVAL = -1 ! default value
END IF
ASSOCIATE (VAL => AVAL)
WRITE(*,'("VAL is ", I0)') VAL
END ASSOCIATE
END SUBROUTINE SUB
Not ideal but allows you to use the same variable name for the argument and in the body of the routine. I shudder to think of the amount of untidy code I've written coping with the lack of default values for optional arguments - roll on F202X.
I hope Fortran to support a popular syntax like
subroutine mysub( x, val = -1 )
integer, optional :: val
or in a more Fortran style
subroutine mysub( x, val )
integer, optional :: val = -1 !! not SAVE attribute intended
but this seems not supported (as of 2016). So some workaround needs to be done by the users' side...
In my case, after trial-and-errors, I settled down to attaching one underscore to the optional dummy argument, so doing something like (*)
subroutine mysub( x, val_)
integer, optional :: val_
integer val
Other people seem to like the opposite pattern (i.e., dummy variable => sep, local variable => sep_, see split() in StringiFor, for example). As seen in this line, the shortest way to set the default value is
val = -1 ; if (present(val_)) val = val_
But because even this line is somewhat verbose, I usually define a macro like
#define optval(x,opt,val) x = val; if (present(opt)) x = opt
in a common header file and use it as
subroutine mysub( x, val_, eps_ )
integer :: x
integer, optional :: val_
real, optional :: eps_
integer val
real eps
optval( val, val_, -1 )
optval( eps, eps_, 1.0e-5 )
print *, "x=", x, "val=", val, "eps=", eps
endsubroutine
...
call mysub( 100 )
call mysub( 100, val_= 3 )
call mysub( 100, val_= 3, eps_= 1.0e-8 )
However, I believe this is still far from elegant and no more than an effort to make it slightly less error-prone (by using the desired variable name in the body of the subroutine).
Another workaround for a very "big" subroutine might be to pass a derived type that contains all the remaining keyword arguments. For example,
#define getkey(T) type(T), optional :: key_; type(T) key; if (present(key_)) key = key_
module mymod
implicit none
type mysub_k
integer :: val = -1
real :: eps = 1.0e-3
endtype
contains
subroutine mysub( x, seed_, key_ )
integer :: x
integer, optional :: seed_
integer :: seed
getkey(mysub_k) !! for all the remaining keyword arguments
optval( seed, seed_, 100 )
print *, x, seed, key% val, key% eps
endsubroutine
endmodule
program main
use mymod, key => mysub_k
call mysub( 10 )
call mysub( 20, key_= key( val = 3 ) )
call mysub( 30, seed_=200, key_= key( eps = 1.0e-8 ) ) ! ugly...
endprogram
This might be a bit close to what is done by some dynamic languages under the hood, but this is again far from elegant in the above form...
(*) I know it is often considered ugly to use CPP macros, but IMO it depends on how they are used; if they are restricted to limited extensions of Fortran syntax, I feel it is reasonable to use (because there is no metaprogramming facility in Fortran); on the other hand, defining program-dependent constants or branches should probably be avoided. Also, I guess it would be more powerful to use Python etc to make more flexible preprocessors (e.g., PreForM.py and fypp and so on), e.g., to allow a syntax like subroutine sub( val = -1 )
Here is an elegant (i.e., short, clear, standard-conforming) solution:
subroutine sub(val)
integer, optional :: val
write(*,'("aval is ", i0)') val_or_default(val, default=-1)
end subroutine
integer function val_or_default(val, default)
integer, optional, intent(in) :: val
integer, intent(in) :: default
if (present(val)) then ! False if `val` is is not present in `sub`.
val_or_default = val
else
val_or_default = default
endif
end function
This uses the fact that optional arguments can still be passed to a function, even when they are not present,
so long as the corresponding dummy argument is also optional.
There is at least one generic implementation of val_or_default on GitHub
for all intrinsic data types.
(They call it optval.)
I wanted to ask some Fortran gurus about this issues I have with an up to date version of the Cray Compiler. I have several warnings that although they do not affect correctness, they will probably do for performance. The warning is:
This argument produces a copy in to a temporary variable.
Here is one of the situations where I get this warning. Within the same file (fem.f90) and module:
call fem( array_local( i, : ), pcor, arcol, inder, &
^
ftn-1438 crayftn: CAUTION FFEM, File = fem.f90, Line = 676, Column = 31
This argument produces a copy in to a temporary variable.
The routine FFEM from where array_local is called looks like:
--------------------------
subroutine ffem( alow, pcor, arcol, inder, iflag )
integer , intent( in ) :: alow(3), pcor(3)
real, intent( in ) :: inder,arcol
integer, intent( out ) :: iflag
integer:: array_local(5,3)
! within in a loop
call fem( array_local( i, : ), pcor, arcol, inder, &
..........
--------------------------
And here is fem subroutine:
--------------------------
subroutine fem (ac, pc, rc, id, flag )
integer, intent( in ) :: ac(3)
.......
--------------------------
I cannot find the way to get rid of that copy in which will definitely slow down my code. I was wondering, does anyone know why this happen, and how can I fix it?
If array_local must be defined as it is and you cannot define it as (5,3) as brady shows, you can consider an assumed shape dummy argument
subroutine fem (ac, pc, rc, id, flag )
integer, intent( in ) :: ac(:)
array passed there can be non-contiguous and still there is no copy, ac will be non-contiguous (strided) too.
You need explicit interfaces for that. That is best achieved by placing the subroutines in a module.
The feasibility of this change depends on your use of array_local elsewhere, but you could swap the order:
integer:: array_local(3,5)
and then call fem:
call fem( array_local( :, i ), pcor, arcol, inder, &
This will allow the compiler to simply send a reference to the appropriate part of the array_local array since columns are ordered contiguously in memory.
I can't tell what is wrong with this free form Fortran program. It does not correctly handle its command line arguments.
It works if I use a static array for the command line argument instead of an allocatable array.
Also, is this a good first Fortran program? Is this the type of problem for which Fortran would be useful? I already know C, C++, and a little bit of D.
module fibonacci
use ISO_FORTRAN_ENV
implicit none
contains
subroutine output_fibonacci(ordinal)
! Declare variables
integer, parameter :: LongInt = selected_int_kind (38)
integer, intent(in) :: ordinal
integer :: count
! integer (kind=LongInt) :: count, compare=2
integer (kind=LongInt), dimension(2,2) :: matrix, initial
matrix=reshape((/ 1, 1, 1, 0 /), shape(matrix))
initial=reshape((/ 1, 0, 0, 1 /), shape(initial))
count = ordinal
! Do actual computations
do while (count > 0)
! If the exponent is odd, then the output matrix
! should be multiplied by the current base
if (mod(count,2) == 1) then
initial = matmul(matrix, initial)
end if
! This is the squaring step
matrix = matmul(matrix, matrix)
count = count/2
end do
write (*,*) initial(1,2)
end subroutine output_fibonacci
end module fibonacci
program main
use, intrinsic :: ISO_FORTRAN_ENV
use fibonacci
implicit none
! The maximum allowed input to the program
integer :: max=200, i, size=20
character, allocatable :: argumen(:)
integer :: error, length, input
allocate(argumen(size))
! write(*,*) argcount
do i=1, command_argument_count()
call get_command_argument(i, argumen, length, error)
read(argumen,*,iostat=error) input
! write(*,*) argument
! write (*,*) input
if (error .ne. 0) then
write(ERROR_UNIT,'(I36.1,A)') input, "is not an integer"
stop (1)
else if (input > max) then
write(ERROR_UNIT,'(A,I36.1,A)') "Input ", input, " is too large"
stop (1)
end if
call output_fibonacci(input)
end do
end program
This line
character, allocatable :: argumen(:)
declares an allocatable array of characters. So the statement
allocate(argumen(size))
makes argumen an array of 20 single-character elements. That's not the usual way of dealing with strings in Fortran and argumen doesn't match (in type or rank) the requirements for the second argument in the call to get_command_argument.
Instead you should write
character(len=:), allocatable :: argumen
to declare argumen to be a character variable of allocatable length. In some contexts you can simply assign to such a variable, e.g.
argumen = 'this is the argument'
without having to previously allocate it explicitly.
With Intel Fortran v14 the call to get_command_argument compiles without warning but on execution the argument argumen isn't automatically allocated and it remains unassigned. I'm honestly not sure if this behaviour is standard-conforming or not. One approach would be to make two calls to get_command_argument, first to get the size of the argument, then to get the argument; like this
do i=1, command_argument_count()
call get_command_argument(i, length=length, status=error)
allocate(character(length)::argumen)
call get_command_argument(i, argumen, status=error)
! do stuff with argument
deallocate(argumen)
end do
Using the name length for the variable to be assigned the value returned by the optional argument called length is legal but a mite confusing. The deallocate statement ensures that argumen can be allocated again for the next argument.
I'll leave you the exercise of declaring, and using, an allocatable array of allocatable-length characters.
Disclaimer: the next two paragraphs contain material which some may find subjective. I will not be entering into any discussion about these parts of this answer.
Is this a good first Fortran program ? It's better than a lot of what I see here on SO. Personally I prefer the consistent use of the modern /= to .ne., < to .lt (etc), I don't use stop if I can avoid it (I usually can), and I'm sure I could find other nits to pick.
Is this the type of problem for which Fortran would be useful? Fortran is useful for all types of problem, though I admit it can be quite challenging using it to write a web server.