Reputation: 31
I am trying to use a variable length string to read some data from NetCDF. In order to use the NetCDF calls I must provide a string large enough to accommodate the data. But I am running into problems.
I stripped down the problem in a weird behavior of the gfortran compiler. At least I think it is so, but maybe it is a Fortran 90 feature.
Here is the sample code:
program test
implicit none
integer clen,slen
character(len=:), allocatable :: string
clen = 10
allocate(character(len=clen) :: string)
slen = len(string)
write(6,*) 'clen,slen,dlen: ',clen,slen,len(string)
string = ' '
write(6,*) 'clen,slen,dlen: ',clen,slen,len(string)
string = 'test'
write(6,*) 'clen,slen,dlen: ',clen,slen,len(string)
end
I would expect to get for all three write statements "10 10 10", since the string I have allocated is of size 10.
However, here is what I get:
clen,slen,dlen: 10 10 10
clen,slen,dlen: 10 10 1
clen,slen,dlen: 10 10 4
It seems as if string gets reallocated every time I assign to it. This is not the behavior I expect.
I probably use an outdated version of gfortran (GNU Fortran (Debian 4.9.2-10) 4.9.2). My question is: will this behavior go away with a newer version of the compiler, or is this a feature of Fortran 90? And if this is a feature, how can I avoid it?
Upvotes: 3
Views: 2026
Reputation: 32366
It seems as if string gets reallocated every time I assign to it.
This is exactly the case. I'll note first that your code isn't Fortran 90 compatible: so-called deferred length character variables were introduced in Fortran 2003.
When a deferred length character variable is the subject of intrinsic assignment (which is what you have here with string=...
) it takes on the length of the expression on the right-hand side. This is similar to the behaviour with allocatable arrays.
After the allocate
statement string
is of length 10, but come
string = ' '
the right-hand side expression is of length 1 (a single blank). This means that string
is deallocated and then reallocated to this new length.
Similarly to arrays, you can retain the length of the left-hand side in an assignment by using a substring:
string(:) = ' '
Such a substring is not subject to reallocation and you'll see the usual rules of fixed-length string assignment (padding or truncation of the right-hand side).
As a final comment, this reallocation is the case for assignment. When you pass string
to a NetCDF procedure which populates the string it won't do such reallocation: the NetCDF procedures will consider the dummy argument as not being of deferred length. Your tests with intrinsic assignment aren't indicative of wider behaviour.
Upvotes: 2