Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

crash writing TAB-separated data (g95)

9 views
Skip to first unread message

v...@york.ac.uk

unread,
Nov 9, 2008, 12:33:29 PM11/9/08
to
I am trying to write files of TAB-separated data. I use a Fortran dll
(compiled with g95) which is called from an external application.
Unfortunately, the program crashes after writing 4.5 files (>8000
lines in each). Here is the relevant part of the code, it writes a 2-
column TAB-separated ASCII file from an array x which has the
following structure: x1,y1,x2,y2 etc (2*n elements altogether)
...
open(unit=13,
file=trim(asciiname),status="REPLACE",action="WRITE",iostat=st)
...
do k=1,n
call real2str(x(2*k-1),str1)
call real2str(x(2*k),str2)
write(13,'(T1,A)') TRIM(str1)//ACHAR(9)//TRIM(str2)
end do
...
subroutine real2str(num,str)
implicit none
integer, parameter :: single_ = kind(0.0)
real(kind=single_), intent(in) :: num
character(len=13), intent(out) :: str
write(str,'(T1,G13.7)') num !convert number to string via internal
file
if (str(1:1)==' ') str=str(2:len(str)) ! remove leading space (e.g.,
if the number was positive)
end subroutine real2str

If I simply use write(13,'(T1,2G13.7)') x, then everything works fine,
but if course it is no longer TAB-separated...
Interestingly, if I replace write(str,'(T1,G13.7)') num with
write(str,*) num in the subroutine, the program crashes after less
than two files.

Any clues?

Thanks!,
Victor

Richard Maine

unread,
Nov 9, 2008, 12:57:35 PM11/9/08
to
<v...@york.ac.uk> wrote:

> the program crashes after writing 4.5 files (>8000
> lines in each).

Sounds to me something like a memory leak. I'd say the most plausible
place for a leal might be the temporary string probably allocated behind
your back for the concatenation in

> write(13,'(T1,A)') TRIM(str1)//ACHAR(9)//TRIM(str2)

Note that I'm not saying there is anything wrong with that line - just
that it seems like a spot that the compiler might most plausibly have
made an error.

This has nothing in particular to do with tabs. The fact that you got a
crash in a different spot when you changed the format used by the
internal write could be explained by the fact that this would give
different trimmed lengths for the strings, and thus different amounts of
memory leaked.

As a workaround, I might suggest something like

write(13,'(3A)') TRIM(str1), ACHAR(9), TRIM(str2)

or you can add the T1 back in, if you really like those. I'm a bit at
loss as to what they are for; doesn't look like any of the T1 things
actually do anything.

Seems to me that I recall seeing a bug somewhat like this elsewhere -
where a compiler did fine with a concatenation with a single TRIM
involved, but leaked memory when there were multiple trims in the same
concatenation of a temporary string. (Maybe it creates multiple
temoraries, but only deallocates one?).

As two unrelated asides:

> open(unit=13, file=trim(asciiname),...

The trim does no harm there, but it is superfluous. The compiler will
trim file names anyway; the standard specifies that.

> if (str(1:1)==' ') str=str(2:len(str)) ! remove leading space (e.g.,
> if the number was positive)

See the adjustl intrinsic for a simple way to remove arbitrary number of
leading blanks like this. It does the same thing as this for the case of
a single leading blank, but is more robust in that it will also handle
multiple blanks.

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

v...@york.ac.uk

unread,
Nov 9, 2008, 1:45:57 PM11/9/08
to
Dear Richard,

Many thanks for your help!

>   write(13,'(3A)') TRIM(str1), ACHAR(9), TRIM(str2)

This still does not work. The problem is with the string assignment.
So simply doing

do k=1,n
str1='1'
str3=str1
end do

causes it to crash after several files (n>8000 in each, str3 and str1
are declared 13 character long)! Commenting out str3=str1 removes the
problem.

But the problem must be related to the fact that it is a dll, or to
file writing/reading, because if I write a short program with a
similar loop and no file writing, it works OK.

Any more thoughts?

> or you can add the T1 back in, if you really like those. I'm a bit at
> loss as to what they are for; doesn't look like any of the T1 things
> actually do anything.

You are right, I just thought that otherwise you will get spaces in
position 1, but I was wrong

> > open(unit=13, file=trim(asciiname),...
>
> The trim does no harm there, but it is superfluous. The compiler will
> trim file names anyway; the standard specifies that.

Thanks, I did not know!

> See the adjustl intrinsic for a simple way to remove arbitrary number of
> leading blanks like this.

Thanks, did not know about this either!

Regards,
Victor

Richard Maine

unread,
Nov 9, 2008, 2:10:32 PM11/9/08
to
<v...@york.ac.uk> wrote:

> > write(13,'(3A)') TRIM(str1), ACHAR(9), TRIM(str2)
>
> This still does not work.

Sorry. Oh well, it was a bit of a stab in the dark. Missed, I guess.

> The problem is with the string assignment.
> So simply doing
>
> do k=1,n
> str1='1'
> str3=str1
> end do
>
> causes it to crash after several files (n>8000 in each, str3 and str1
> are declared 13 character long)! Commenting out str3=str1 removes the
> problem.

I'd not be confident of that conclusion without seeing the whole
context. Particularly since we seem to be talking about memory leaks (I
still think that likely), tracking the actual cause can be subtle. Just
because you changed that one line and it changed the result doesn't
necessarily mean that the actual problem is in that line; it could well
be affecting the memory allocations in other lines.

> But the problem must be related to the fact that it is a dll, or to
> file writing/reading, because if I write a short program with a
> similar loop and no file writing, it works OK.

That's at least possible. I don't do dlls (or much in Windows at all),
so others can probably answer that part better. I do recall of hearing
about some things that didn't work right in dlls with some compilers,
but I couldn't tell you details.

> Any more thoughts?

I'm about out of ideas on this one at the moment. Maybe other people
here?

e p chandler

unread,
Nov 9, 2008, 3:49:31 PM11/9/08
to

Mismatched calling convention between host and dll? Usually this
causes an immediate crash or error exit. If the called routine is
expected to remove arguments from the stack (stdcall) but does not
(cdecl) then there is a memory leak of stack space.

There are only a few true "GOTCHA"s with DLLs. One involves
restrictions on COMMON blocks. Another involves console I/O. If the
DLL does not open a console window but does console I/O ... BOOM.

The OP should try putting his problem code in a subroutine and
compiling it with a Fortran main program. Then compile the subroutine
to a DLL and staticly link it to a Fortran main program. (I guess
functions would be OK too...).

A DLL should not be as fussy as the OP reports. Internally a DLL is
like an EXE file but with a different initialization point and
different routine entry points. I expect the real error is somewhere
else in code not shown.

Last, I do not think that the OP has to be so strict with his
formatting. Generally TAB delimited files also ignore leading and
trailing blanks around data items. (Excel TAB & SPACE delimited does
not.) Also the T1 edit descriptor seems un-necessary.

How about

WRITE(13,'(G13.7,A,G13.7)') x(2*k-1),achar(9),x(2*k)

?

I still think the real problem is elsewhere.

-- e


v...@york.ac.uk

unread,
Nov 9, 2008, 4:48:33 PM11/9/08
to
> Mismatched calling convention between host and dll?

Many thanks for this suggestion! I am calling Fortran dll from an
AutoIt program. AutoIt can use either stdcall or cdecl. Default is
stdcall, so I have been compiling Fortran dll with -mrtd switch. Now I
compiled Fortran dll without -mrtd switch, and told AutoIt to use
cdecl, and everything works OK. I do not understand though...

I do not know what the problem is. The whole code is too long to show
here. It does have allocatable arrays but I have tried replacing them
with explicit ones with the same result. Otherwise the program is
quite straightforward, it's just reading binary files using
access="STREAM", and saving them as formatted ASCII with various
options.

As an aside, am I doing the right things with arrays? I have a
subroutine which reads binary file and returns the data as an array.
So I declare an allocatable array as an argument in the subroutine:
real(kind=single_), allocatable, dimension(:), intent(out) :: x. I
then allocate memory, read the array from the file and return it. I do
not deallocate the array in the subroutine as it needs to be passed
back as an argument. In the main program I declare the array as
allocatable and also have explicit interface for the subroutine. I
call the subroutine in the main program, then deallocate the array in
the main program before calling the subroutine again. Is this correct?
Anyway, this is not the problem as I have tried explicit declarations.

> The OP should try putting his problem code in a subroutine and
> compiling it with a Fortran main program. Then compile the subroutine
> to a DLL and staticly link it to a Fortran main program.

Will try, thanks.

> Last, I do not think that the OP has to be so strict with his
> formatting. Generally TAB delimited files also ignore leading and
> trailing blanks around data items. (Excel TAB & SPACE delimited does
> not.)

Excel is key here. I have an old Excel macros which does not
understand leading blanks. Of course I can easily change this but I'd
rather not for compatibility reasons - several people in my group have
(several) copies of this macros and a new version will cause
confusion.

Thanks!

Richard Maine

unread,
Nov 9, 2008, 5:33:52 PM11/9/08
to
<v...@york.ac.uk> wrote:

> As an aside, am I doing the right things with arrays? I have a
> subroutine which reads binary file and returns the data as an array.
> So I declare an allocatable array as an argument in the subroutine:
> real(kind=single_), allocatable, dimension(:), intent(out) :: x. I
> then allocate memory, read the array from the file and return it. I do
> not deallocate the array in the subroutine as it needs to be passed
> back as an argument. In the main program I declare the array as
> allocatable and also have explicit interface for the subroutine. I
> call the subroutine in the main program, then deallocate the array in
> the main program before calling the subroutine again. Is this correct?

That all sounds fine.

e p chandler

unread,
Nov 9, 2008, 8:05:52 PM11/9/08
to
On Nov 9, 4:48 pm, v...@york.ac.uk wrote:
> > Mismatched calling convention between host and dll?
>
> Many thanks for this suggestion! I am calling Fortran dll from an
> AutoIt program. AutoIt can use either stdcall or cdecl. Default is
> stdcall, so I have been compiling Fortran dll with -mrtd switch. Now I
> compiled Fortran dll without -mrtd switch, and told AutoIt to use
> cdecl, and everything works OK. I do not understand though...

[snip]


>
> > Last, I do not think that the OP has to be so strict with his
> > formatting. Generally TAB delimited files also ignore leading and
> > trailing blanks around data items. (Excel TAB & SPACE delimited does
> > not.)
>
> Excel is key here. I have an old Excel macros which does not
> understand leading blanks. Of course I can easily change this but I'd
> rather not for compatibility reasons - several people in my group have
> (several) copies of this macros and a new version will cause
> confusion.
>
> Thanks!

I see now. Excel may well load the looser format itself as a workbook,
but if you are reading the file as a text file in through VBA, then
there could be trouble. [Yes VBA can read/write files just like older
MS Basics without resorting to the file-system-object provided by
Windows-Scripting-Host.]

-- e

Terence

unread,
Nov 10, 2008, 5:49:18 PM11/10/08
to
Excel accepts several delimited input formats.
These are the ones I know about; there may be others (nowadays):-

TAB

spaced

comma (between fields, using apostrophes around text items with inner
punctuation or spaces)

comma and colon: (where colon is between fileds and comma between
multiples items in the current field.

Since any major rank delimiter (e.g.colon) is found first within a new
line input, Excel knows which format is in use.

robin

unread,
Nov 13, 2008, 6:17:27 PM11/13/08
to
<v...@york.ac.uk> wrote in message
news:a71255b7-c425-4cce...@c36g2000prc.googlegroups.com...
Dear Richard,

>Many thanks for your help!

>> write(13,'(3A)') TRIM(str1), ACHAR(9), TRIM(str2)

>This still does not work. The problem is with the string assignment.
>So simply doing

>do k=1,n
> str1='1'
> str3=str1
>end do

>causes it to crash after several files (n>8000 in each, str3 and str1
>are declared 13 character long)! Commenting out str3=str1 removes the
>problem.

>But the problem must be related to the fact that it is a dll, or to
>file writing/reading, because if I write a short program with a
>similar loop and no file writing, it works OK.

Sounds like you may have an array subscript out of range.
Do you have array and string bound checking turned on?


v...@york.ac.uk

unread,
Nov 16, 2008, 6:05:30 PM11/16/08
to
> Sounds like you may have an array subscript out of range.
> Do you have array and string bound checking turned on?

Yes I am pretty sure this is not the problem. The problem was resolved
after I compiled dll without -mrtd script and used cdecl calling
method.

0 new messages