Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29273 Discussions

Storing/Retrieving TYPEs with ALLOCATABLE components

Jugoslav_Dujic
Valued Contributor II
876 Views
I'm revising some old software of mine (CVF 6.6C), which used Form='BINARY' files for storage. I converted most of the data structure into TYPEs with nested ALLOCATABLE components.
Currently, the saving code looks like:
OPEN (11, FILE=szNtrFile, FORM='BINARY')
WRITE(11) CURR_VERSION, tNT, tSec, tBrd
DO iB=1,tNT%nBoards
WRITE(11) tBrd(iB)%tEn
END DO
where tBrd is an array of type T_BOARD containing allocatable component tEn(:) of type T_ENTRY.
My understanding is that WRITE in this case just dumps whatever happens to be in tBrd, including array descriptor of tEn (i.e. TRANSFER(tBrd, (/0_1/))).
However, retrieval of such file doesn't go without problem (in a subsequent invocation of program):
READ(11, IOSTAT=iErr) NT
READ(11, IOSTAT=iErr) Sec
READ(11, IOSTAT=iErr) tBrd
ALLOCATE(tBrd(NT%nBoards))
DO i=1,NT%nBoards
DEALLOCATE(tBrd(i)%tEn, STAT=iSt)
ALLOCATE(tBrd(i)%tEn( tBrd(i)%nEntries))
READ(11) tBrd(i)%tEn
END DO
Without previous DEALLOCATE, the allocate line fails at run time with message "the array isalready allocated". With the deallocate, I got "user breakpoint called from xxxx" somewhere in NTDLL.dll followed by "Heap: Invalid Address specified to RtlFreeHeap." in the debugger. The program appears to work after that,but I don't feel comfortable about it. OK, this is easily explainable by the fact that I'm loading an invalid descriptor tBrd%tEn from the file... but how can I avoid it?
Basically, I seem to have managed that tEn component has "undefined" allocation status (which is not possible according to Standard, but then BINARY files aren't standard either).
I'm open to suggestions how to workaround the problem; binary file is a must, but some suitable method for avoiding either WRITEing or READing a structure with wrong descriptor is welcome.
Jugoslav
0 Kudos
8 Replies
Steven_L_Intel1
Employee
876 Views
Quoting from the TR: "As with ultimate pointer components, variables containing ultimate allocatable array components are forbidden from appearing directly in input/output lists - the user shall list any allocatable array or pointer component for i/o"
[The last phrase seems a bit garbled to me, but I think it's saying that you have to list the component directly in the I/O list so that its value is read or written, rather than trying to read or write the descriptor.]
It would not astonish me if the compiler did not detect this as a standards violation.
Now, this does not seem to be what you are doing, if I understand it correctly. When you write tBrd(iB)%tEn, if I have it right that tEn is an allocatable array component, what should be written is the values in the array, if any (a dereference, if you will), NOT the descriptor. If the array is unallocated, then the program is invalid as you're not allowed to reference an unallocated array.
Similarly on a read, the array component would already have to be allocated.
It could be that you have found an aspect of this feature that is not properly implemented in the compiler....
0 Kudos
Jugoslav_Dujic
Valued Contributor II
876 Views

Quoting from the TR: "As with ultimate pointer components, variables containing ultimate allocatable array components are forbidden from appearing directly in input/output lists - the user shall list any allocatable array or pointer component for i/o"

It's a bit garbled to me too... but I parse it as if I do violate the standard, as I store tBrd array -- which is a variable containing ultimate allocatable array components-- prior to the values of its tEn components. If I parse it well, then there's no way to save/retrieve tBrd at all (which is really painful, as it contains lots of other non-allocatable stuff).

I'll pass this on to comp.lang.fortran to see if language gurus have to say something about it.

Jugoslav

0 Kudos
Steven_L_Intel1
Employee
876 Views
It would help if you show the declaration (cut down, perhaps) of the array and its type.
0 Kudos
Steven_L_Intel1
Employee
876 Views
I did an experiment and the compiler will not allow you to put a variable with an allocatable or pointer component in an I/O list. Since you didn't provide a complete sample, I'm not sure what you're doing, but it looks to me as if you're reading and writing the values, not the descriptor.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
876 Views
Steve Lionel wrote:
| On Wed, 03 Mar 2004 20:42:57 -0800, Richard Maine
| wrote:
|
|| I'm somewhat surprised that the compiler didn't gripe about the
|| ilegality of these I/O lists? That's not something it is required
|| to disgnose, but I'd biatch anyway...that is assuming you have full
|| diagnostic options turned on.
||
||| It would not astonish me if the compiler did not detect this as a standards
||| violation.
||
|| Yep. That's what I thought also. Same reasoning.
|
| Jugoslav hadn't included his declarations when he posted on the user forum, so
| I wasn't entirely sure what he was doing. I wrote my own example and the
| Intel 8.0.042 compiler properly complained (as a regular error, not just a
| standards warning) when a derived type with an ultimate pointer or allocatable
| component was in an I/O list. For example:
|
| t.f90(29) : Error: Variables containing ultimate allocatable array components
| are forbidden from appearing directly in input/output lists. [R1]
| write (1) r1
| ----------^
|
| (CVF 6.6C gives the same error.)

I wrote an array of such. However, 6.6C didn't complain. When I tried
a scalar, it didn't complain either. Here's the complete relevant code:

MODULE NSBKMOD

TYPE T_CONTRACT
INTEGER(1):: iSuit = 0
INTEGER(1):: iLevel = 0
INTEGER(1):: iTricks = 0
INTEGER(1):: iFlags = 0
END TYPE T_CONTRACT

TYPE T_ENTRY
INTEGER(1):: iPair(2) = (/0, 0/)
INTEGER(1):: iFlags = 0
INTEGER(1):: iReserved = 0
REAL:: fResult = 0.
REAL:: fImp(2) = (/0., 0./)
REAL:: fProc(2) = (/0., 0./)
TYPE(T_CONTRACT):: tCo
INTEGER:: iReserved2
END TYPE T_ENTRY

TYPE T_BOARD
INTEGER:: nEntries = 0
INTEGER:: iFlags = 0
TYPE(T_ENTRY), ALLOCATABLE:: tEn(: )
END TYPE T_BOARD

TYPE(T_BOARD), ALLOCATABLE:: tBrd(: )

END MODULE
!===============================
SUBROUTINE SaveNtrFile(szNtrFile)

USE NSBKMOD
USE GLOBALS

IMPLICIT NONE

CHARACTER(*):: szNtrFile

INTEGER:: iB

OPEN (11, FILE=szNtrFile, FORM='BINARY')
WRITE(11) CURR_VERSION, tNT, tSec, tBrd
DO iB=1,tNT%nBoards
WRITE(11) tBrd(iB)%tEn
END DO
...
CLOSE(11)


CVF 6.6C doesn't complain about trying to WRITE tBrd (neither if
I replace tBrd with a dummy scalar T_BOARD). I didn't manage to
find time to try IVF 8.

| Without seeing a complete example, I have to assume that Jugoslav's code that
| compiled had the array itself and not a derived type with an array component
| in the I/O list. If there's an example that shows otherwise, I'd like to see
| it.

I wanted to, but the user forum has been giving me "Access denied" for en tire
day yesterday.

| Interesting. I wonder what the compiler sees different in this case? We'll
| investigate - thanks.

If a sample workspace would help, I don't mind sharing it. Premier,
direct e-mail or...?


0 Kudos
Steven_L_Intel1
Employee
876 Views
I managed to come up with a compilable example that did not get the error it should.
The login issue with the forum should be fixed - I had seen it too on occasion.
0 Kudos
Steven_L_Intel1
Employee
876 Views
It seems the key is whether the allocatable component is itself a derived type. If it is, the compiler misses giving the error. But if it's an intrinsic type, it does give the error. I have submitted this to engineering.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
876 Views

Thanks Steve.

I redesigned the code so that it now stores/retrieves only nEntries and iFlags components of tBrd.

Jugoslav
0 Kudos
Reply