This question already has an answer here:
Variable format
(1 answer)
Closed 2 years ago.
I used to the Intel fortran compiler which supports using the <n> extension like
write(*, '(<n>(2I4))') (i, 2*i, i=1,n)
To illustrate, I give a s1_fprint.f90 subroutine as follows
subroutine fprint(name,bb)
IMPLICIT NONE
character(len=*), intent(in) :: name
real, intent(in) :: bb(:,:)
integer :: column=10
integer i,j,k,m,n
n = size(bb,1)
m = size(bb,2)
write(*,'(1a)')name
do k=0,m/column-1
write(*, '(1x,<column>i16)')(i,i=k*column+1,(k+1)*column)
write(*,'(1i10,<column>f)')(i,(bb(i,j),j=k*column+1,(k+1)*column),i=1,n)
write(*,'(/)')
end do
if(mod(m,column)/=0)then
write(*, '(1x,<m-m/column*column>i16)')(i,i=m/column*column+1,m)
write(*,'(1i10,<m-m/column*column>f)')(i,(bb(i,j),j=m/column*column+1,m),i=1,n)
write(*,'(/)')
endif
end subroutine fprint
Now, I change the Intel fortran compiler to gfortran, then I test (t1_useSur.f90)
above subroutine in gfortran as follows:
program main
implicit none
real :: A(2,3) = reshape([1.2, 2.3, 3.4, 4.5, 5.6, 6.7], [2,3])
call fprint('A',A)
end program main
which should show us something like
A
1 2 3
1 1.2000000 3.4000001 5.5999999
2 2.3000000 4.5000000 6.6999998
However, in gfortran compiler when I run
gfortran t1_useSur.f90 s1_fprint.f90 -o out
./out
there are many errors as
.\s1_fprint.f90:14.17:
write(*, '(1x,<column>i16)')(i,i=k*column+1,(k+1)*column)
1
Error: Unexpected element '<' in format string at (1)
.\s1_fprint.f90:15.19:
write(*,'(1i10,<column>f)')(i,(bb(i,j),j=k*column+1,(k+1)*column),i=1,n)
1
Error: Unexpected element '<' in format string at (1)
.\s1_fprint.f90:19.17:
write(*, '(1x,<m-m/column*column>i16)')(i,i=m/column*column+1,m)
1
Error: Unexpected element '<' in format string at (1)
.\s1_fprint.f90:20.19:
write(*,'(1i10,<m-m/column*column>f)')(i,(bb(i,j),j=m/column*column+1,m),i=
1
Error: Unexpected element '<' in format string at (1)
Since the <n> extension is not supported by gfortran, how can fix these problems?
Near dupe Variable format statement when porting from Intel to GNU gfortran
For the 1-dim cases like (i,i=...) :
If you have (or get) a version of gfortran that supports F08, which browsing https://gcc.gnu.org/onlinedocs/ appears to be around 4.6.4 up, use * as the count like (1x,*i16)
Otherwise, use the old-as-the-hillsF77 trick: since format repetitions or items 'beyond' the data list are ignored, just use a repetition count that is at least as big as the data will ever be (but not more than HUGE(0)) here (1x,10i16) is actually enough but something like (1x,999i16) makes it much more obvious
or if you like extra work, do on-the-fly like the 2-dim case below
For the 2-dim cases like (i,(bb(i,j),j=...),i=...) which currently use format looping to insert record breaks either:
reduce to 1-dim by making the record breaks into separate WRITEs:
do i=...
write(*,'(1i10,*f)') i,(bb(i,j),j=...)
end do !i
generate the correct count on-the-fly:
character(len=20) fmt
...
write(fmt,'(a,i0,a)') '(1i10,', numcols_expression, 'f)'
write(*, trim(fmt)) (i,(bb(i,j),j=...),i=...)
... or ...
write(fmt,'(i0)') numcols_expression
write(*, '(1i10,'//trim(fmt)//'f)') (i,bb(i,j),j=...),i=...)
PS: you don't actually need 1i10 just i10, but I left it for consistency. Also rather than a loop for the full chunks then an if for the partial chunk, which have to be kept in sync, I would probably do:
do k=1,m,column
l=min(k+column-1,m)
... print chunk for i=k,l (numcols is l-k+1) ...
end do !k
Running Intel Parallel Studio 2015 and Visual Studio 2012. Fortran 2003 compatibility turned on.
Is there an issue with the following code because it caused a very confusing (for me at least) heap corruption error on my machine and I'm trying to find out if it is something I'm not understanding correctly or a compiler bug.
character(len=200), dimension(:), allocatable :: inFNs
real*8, dimension(:), allocatable :: times
inFNs = (/ "file1.dat", "file2.dat", &
"file3.dat", "file4.dat", &
"file5.dat", "file6.dat" /)
allocate(times(SIZE(inFNs))
!more code below
The code would crash without a stack trace during the allocation of times, and it would tell me that a heap corruption occurred in a window dialog in debug mode.
The way I determined there was an issue with inFNs was because the issue would occur during a later allocate call if I moved the times allocation to be above inFNs.
The error has seemed to go away (knock on wood) by changing the declaration line to:
character(len=:), dimension(:), allocatable :: inFNs
I'm sorting through another issue in my code before I can know for sure.
In Response to Duplicate Question:
This is not a duplicate of the question suggested for so many reasons that I'm truly confused as to the marking. This question deals specifically with the syntax of an allocatable array of character arrays as opposed to alloctable arrays in general. This question deal with a potential compiler bug with Intel Visual Fortran while the other is a question on differences between Intel Fortran and gFortran. This question deals with a silent crash and heap corruption while attempting to use a separate array whereas the other deals with whether or not the array in question is considered allocated after an operation.
Even more to the point the answer in the second question is irrelevant to the issue present in this question as that option being turned on or off doesn't affect the issue presented.
To say these two questions are identical is like saying I was encountering crash with the following code
real :: number
number = 4.d0
and someone asking another question asking why there is an issue with the following
real :: number
number = 4
call add3ToDouble(number)
subroutine add3ToDouble(a)
real*8 :: a
a = a + 3.d0
end subroutine add3ToDouble
and saying the answer to both being "Because ifort defaults to real(kind=4)"
I'm trying to compile some old fortran77 programs with gfortran and getting error with allocatable arrays.
If I define arrays in f90-style, like:
REAL*8,allocatable::somearray(:)
everything is fine, but in those old programs arrays defined as:
REAL*8 somearray[ALLOCATABLE](:)
which cause gfortran error output:
REAL*8,allocatable::somearray[ALLOCATABLE](:)
1
Fatal Error: Coarrays disabled at (1), use -fcoarray= to enable
I really wish to avoid rewriting whole programs to f90 style, so, could you please tell me, is there any way to force gfortran to compile it?
Thanks a lot.
For standard checking you can use -std flag
-std=std
Specify the standard to which the program is expected to conform, which may be one of f95',f2003', f2008',gnu', or `legacy'.
To "force" gfortran to compile your code, you have to use syntax it recognizes
I'd probably go for search and replace. For example,
sed 's/\(REAL\*8\)[[:blank:]]\+\([^[]\+\)\[ALLOCATABLE\]\(.*\)/\1, allocatable :: \2\3/' <old.source> > <new.source>
where sed is available.
Of course, be careful with sed :).
In any case, as it seems your code was written in some non-standard version of old
Fortran, you'll probably need to make changes in any case.
For what it's worth the Intel Fortran compiler (v13.something) compiles the following micro-program without complaint. This executes and writes 10 to the terminal:
REAL*8 somearray[ALLOCATABLE](:)
allocate(somearray(10))
print *, size(somearray)
end
Given the history of the Intel compiler I suspect that the strange declaration is an extension provided by DEC Fortran, possibly an early implementation of what was later standardised in Fortran 90.
See the example below
program test
character(10),dimension(5):: models = (/"feddes.swp", "jarvis89.swp", "jarvis10.swp" , "pem.swp", "van.swp"/)
end
The following error is returned:
Different CHARACTER lengths (10/12) in array constructor at (1)
There is no error with ifort compiler. Why does it happen with gfortran and is there any way to circumvent this problem?
You have some lengths 12 in the constructor, so it may be better to use length 12.
Also, use instead
character(len=12), dimension(5) :: models = [character(len=12) :: "feddes.swp", &
"jarvis89.swp", "jarvis10.swp", "pem.swp", "van.swp"]
Possibly even better, if you have compiler support, is
character(len=*), dimension(*) :: ...
The original code is accepted by ifort but it is not standard fortran, hence the error from gfortran. If you supply the option -std to ifort it will print warnings when the compiler allows extensions such as this.
My code (stripped down to what I think is relevant for this question) is
PROGRAM test
IMPLICIT NONE
CHARACTER(len=37) input
CHARACTER(len=:), allocatable :: input_trim
WRITE(*,*) 'Filename?'
READ(*,*) input
ALLOCATE(character(len=LEN(TRIM(input))) :: input_trim)
input_trim=trim(input)
.
.
.
END PROGRAM test
It works fine with Intel's Fortran compiler, however gfortran gives me a couple of errors, the first one being in the line saying
CHARACTER(len=:), allocatable :: input_trim
I'm not sure which compiler is 'right' regarding the Fortran standard. Plus I don't know how to achieve what I need in a different way?! I think what I'm doing is more of a workaround anyway. What I need is a character variable containing exactly the filename that was entered with no following spaces.
EDIT: The error is "Syntax error in CHARACTER declaration".
gfortran --version gives me "GNU Fortran (GCC) 4.4.7 20120313 (Red Hat 4.4.7-3)"
EDIT 2: You're right regarding the allocate: With ifort, I don't need it. And gfortran crashes before that so maybe it doesn't need the allocate either but I cannot test this at the moment...
This
character (len=:), allocatable :: input_trim
is certainly syntactically correct in Fortran 2003. You don't say what the error that gfortran raises is, so I can't comment on why it doesn't accept the line -- perhaps you have an old version of the compiler installed.
With an up-to-date Fortran compiler (eg Intel Fortran v14.xxx) you don't need to allocate the character variable's size prior to assigning to it, you can simply write
input_trim = trim(input)
Note that
read(*,*) input_trim
won't work.
With Absoft Fortran, this compiles (haven't run with it yet):
character,dimension(:),allocatable::Line_for_IO !Metcalf,Reid,Cohen p. 107, w/mods
if(allocated(Line_for_IO)) deallocate(Line_for_IO)
allocate(Line_for_IO(7*n+40))