Home     |     .Net Programming    |     cSharp Home    |     Sql Server Home    |     Javascript / Client Side Development     |     Ajax Programming

Ruby on Rails Development     |     Perl Programming     |     C Programming Language     |     C++ Programming     |     IT Jobs

Python Programming Language     |     Laptop Suggestions?    |     TCL Scripting     |     Fortran Programming     |     Scheme Programming Language


 
 
Cervo Technologies
The Right Source to Outsource

MS Dynamics CRM 3.0

Fortran Programming Language

internal read of character array. F/ifort differences


I have a subroutine which reads a line of input as text, and which
then uses an internal file to split the line into fields, e.g.

Main Prog has: character(len=20), dimension(80) :: Headers

+

subroutine Read_Headers(Headers)
character(len=*), dimension(:), intent(out) :: Headers
character(len=200) :: inputline
integer :: ios

 read(unit=*,fmt="(a)") inputline    ! e.g. " yy mm dd val1 val2"
 read(unit=inputline,fmt=*,iostat=ios)  Headers

This technique compiles and works great with F and gfortran,
assigning Headers(1) to "yy", Headers(2) to "mm", etc., but when I use
ifort I get an iostat error and Headers isn't set at all.

If I define a temporary array xHeaders with say len=20, dimension(80)
and then copy this to Headers it also works, so I can get my work
done. Still, this is the first time I have found that
ifort does not compile an F-compliant program to give the same
results. Does anybody know the rules on this? Thanks.

David Simpson <david.simp@met.no> wrote:
> Main Prog has: character(len=20), dimension(80) :: Headers
...
>  read(unit=*,fmt="(a)") inputline    ! e.g. " yy mm dd val1 val2"
>  read(unit=inputline,fmt=*,iostat=ios)  Headers
> This technique compiles and works great with F and gfortran,
> assigning Headers(1) to "yy", Headers(2) to "mm", etc., but when I use
> ifort I get an iostat error and Headers isn't set at all.

I'd want to know what the indicated error was. Numeric iostat values,
unfortunately, aren't meaningful unless you have the appropriate
compiler documentation somewhere. I look forward to f2003 srtandardizing
iomsg so that I can get a human-understandable diagnostic without the
following trick.

Temporarily take the iostat specifier out of the read statement. The
program will then presumably abort and output an explanatory error
message.

Lacking that, one thing I notice is that your data has fewer than the 20
values that the read requires. You might just be hitting an end-of-file
condition. If you are counting on getting partial data out of a read
that hits an end-of-file, that is nonstandard and nonportable.

> If I define a temporary array xHeaders with say len=20, dimension(80)
> and then copy this to Headers it also works,

Hmm. That argues against it being the end-of-file issue. Puzzling.

--
Richard Maine                    | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle           |  -- Mark Twain

Richard Maine wrote:
> David Simpson <david.simp@met.no> wrote:
>>Main Prog has: character(len=20), dimension(80) :: Headers
>> read(unit=*,fmt="(a)") inputline    ! e.g. " yy mm dd val1 val2"
>> read(unit=inputline,fmt=*,iostat=ios)  Headers
>>This technique compiles and works great with F and gfortran,
>>assigning Headers(1) to "yy", Headers(2) to "mm", etc., but when I use
>>ifort I get an iostat error and Headers isn't set at all.

(snip)

>>If I define a temporary array xHeaders with say len=20, dimension(80)
>>and then copy this to Headers it also works,

So there is something about Headers that it doesn't like.

character(len=*), dimension(:), intent(out) :: Headers

I don't believe that (len=*) is a problem.  I it also assumed
shape, so would require the appropriate interface which was
not shown.  That would be my guess.

-- glen

On May 26, 5:32 am, David Simpson <david.simp@met.no> wrote:

> I have a subroutine which reads a line of input as text, and which
> then uses an internal file to split the line into fields, e.g.

> Main Prog has: character(len=20), dimension(80) :: Headers

> +

> subroutine Read_Headers(Headers)
> character(len=*), dimension(:), intent(out) :: Headers
> character(len=200) :: inputline
> integer :: ios

>  read(unit=*,fmt="(a)") inputline    ! e.g. " yy mm dd val1 val2"

What is the output when you insert the line

write (*,*) "inputline = '" // trim(inputline) // "'"

?

Many thanks for the various suggestions. I have made a standalone
small
module and test programme that can reproduce these errors quickly.

In answer to the suggestions:

1) If I remove the iostat test, I get:

forrtl: severe (24): end-of-file during read, unit -5, file Internal
List-Directed Read

So the error does seem to be linked to hitting the end of the record/
file
as you suggest.

I tried again  using xHeaders instead of Headers. With no iostat test
I get the same error message. With an iostat test xHeaders is indeed
set the way I want, with xHeaders = "yy", etc.

There seems to be a big difference in behaviour between the treatment
of the
array defined by the subroutine argument Headers, and the local
argument xHeaders. Note that I have now dimensioned xHeaders with
size(Headers), and get the same good (or wanted)  behaviour  from
xHeaders.

2) I don't use explicit interfaces, but as you can see from the code
below I use a stand-alone module, so the interface is explicit anyway.
Also,
this code compiles and runs great under F, which is usually my
favourite
way to code for portability.

3) I added this output test, and it looks fine, the code below
producing:

 inputline = ' yy mm dd v1 v2'
 Headers1:yy
 Headers2:mm

So, hitting the end of the record before filling the array is causing
the problem, but only when the array is the subroutine argument.

The behaviour I want (fortran just splits the field for me) is of
course very useful, since I am using this to essentially count and
assign the fields of an input array of unknown size. As an alternative
I could process "inputline" through a function to search for spaces
and/or comma-separation, which sounds like a more portable solution,
but would require another piece of code.  Sounds like this would be
the
best approach for now though.

Anyway, below I give the simplified code. Thanks again,  Dave

==========================================================
module Headers_ml
 implicit none
 public :: Read_Headers
contains
 subroutine Read_Headers(inputline,Headers)
   character(len=*), dimension(:), intent(out) :: Headers
   character(len=*),intent(in) :: inputline
   character(len=20), dimension(size(Headers)) :: xHeaders
   integer :: ios

   !WORKS:
   read(unit=inputline,fmt=*,iostat=ios)  xHeaders

   print *, "inputline = '" // trim(inputline) // "'"
   !FAILS: read(unit=inputline,fmt=*,iostat=ios)  Headers
   !FAILS; read(unit=inputline,fmt=*)  Headers
   print *, "Headers1:", trim(xHeaders(1))
   print *, "Headers2:", trim(xHeaders(2))
 end subroutine Read_Headers
end module Headers_ml
===========================================================
program TestH
  use Headers_ml
  character(len=200) :: inputline
  character(len=20), dimension(10) :: Headers
  inputline = " yy mm dd v1 v2"
  call Read_Headers(inputline,Headers)
end program TestH
===========================================================
Compiled with
ifort Headers.f90 TestH.f90

David Simpson <david.simp@met.no> wrote:
> I have made a standalone small module and test programme that can
> reproduce these errors quickly.

Excellent! That helps make sure that there aren't any extraneous factors
that could be confusing things. I don't have iFort handy to play with,
but I can still look at teh code with other compilers and I can study it
much more carefully by eyeball than I can do with isolated snippets.

> 1) If I remove the iostat test, I get:

> forrtl: severe (24): end-of-file during read, unit -5, file Internal
> List-Directed Read

> So the error does seem to be linked to hitting the end of the record/
> file as you suggest.

Ok. That helps explain things. That part I would expect. Indeed it is
what the standard requires without the iostat.

With the iostat, your program is nonstandard because you are referencing
undefined variables. The variables in a read statement are undefined if
you hit and end-of-file. As a general rule, you should not use an iostat
specifier and then ignore the return value. If you are going to ignore
the return value, it is better to omit the iostat specifier completely;
that way you will at least get an error message if something goes wrong.

As I mentioned, the standard says that it is "illegal" (well,
nonstandard) to reference an undefined variable. Many people
misunderstand the consequences that this implies. It doesn't mean that
your program necessarily won't run. Instead, it means that you might get
different resultsfr on different compilers or situations. The code might
give an error message. It might happen to run as expected. It might give
unexpected values for the variable in question. All those are reasonably
plausible. Stranger things are technically allowed, but are less likely
(at least as a direct result; if you use an undefined variable as an
arrsy index, then the strange value case can cause out-of-bounds
references, which can plausibly have lots of symptoms).

> There seems to be a big difference in behaviour between the treatment of
> the array defined by the subroutine argument Headers, and the local
> argument xHeaders.

That one puzzled me quite a bit, enough so that it threw me off track
for a while.

Took me a while, but I think I finally figured out at least roughly. I
think it relates to the dummy argument being assumed shape. because the
dummy is assumed shape, it could, in principle, be stored in
discontiguous memory. Your particular case isn't, but the subroutine has
to be able to handle cases that are. I suspect that some of the I/O
processing is done using a contiguous temporary and then later copied to
the possibly discontiguous dummy argument. The copying part probably
doesn't happen until after the end-of-file is detected.

With the local array, perhaps it is using the array directly instead of
using a compiler temporary. Thus, when the end-of-file is detected, the
partial results happen to be left in your array.

Please note that this behavior of getting partial results is *NOT*
specified by the standard. It is solely a side effect of the way the
compiler happens to implement things. What you have is nonstandard and
nonportable code that is not guaranteed to work. It could, for example,
break with a new release of the compilers that it now appears to work
on.

> The behaviour I want (fortran just splits the field for me) is of
> course very useful, since I am using this to essentially count and
> assign the fields of an input array of unknown size.

Yes, I understand the utility. I once got bit by something very simillar
myself. In my case, it was a record that was too short rather than an
end-of-file; and my case used unformatted input. But I was expecting
simillar partial data to be valid. Worked on some compilers, but I had
to redo my code when I found it was nonportable. That was quite a while
ago (about 25 years or a little more).

> As an alternative
> I could process "inputline" through a function to search for spaces
> and/or comma-separation, which sounds like a more portable solution,
> but would require another piece of code.  Sounds like this would be
> the best approach for now though.

Yes, some variant of that would be what I'd suggest. Yes, it requires a
little more code, but not actualy a large amount. The result is
standard-conforming and portable.

--
Richard Maine                    | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle           |  -- Mark Twain

OK! Many thanks for the clear explanations. I'll use iostat more
carefully in future, and for this job I will code a routine to split
inputline properly. It has been good to catch this now, since this
small bit of code is part of a larger air-pollution model that we plan
to release to the public-domain later this year. Portability is
needed!

Thanks again,

Dave

On May 28, 1:46 am, David Simpson <david.simp@met.no> wrote:
...
> ... code is part of a larger air-pollution model that we plan
> to release to the public-domain later this year. Portability is
> needed!

...

Then you will want to compile/test w/ as many compilers as you can and
be sure to use all of the facilities of the compilers' standard-
conformance checking options to try to ensure particular extensions or
idioms supported by your favorite toolset aren't remaining.  It's
surprising how easy it is to find after a number of years that old
habits aren't standard-conforming but carried over from a compiler
extension of an earlier compiler one used extensively!  (DAMHIKT :
()  :)

Add to del.icio.us | Digg this | Stumble it | Powered by Megasolutions Inc