|
|
 |
 |
 |
 |
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 : () :)
|
 |
 |
 |
 |
|