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

Character allocation question

nvaneck
New Contributor I
2,162 Views
I have a place where I allocate a character vector of programatically determined length, i.e.,

ALLOCATE (STRING(LRECL))

I then pass it to a subroutine where is is defined as CHARACTER RECORD*(*). Before V12, L=LEN(RECORD) gave me the length of STRING, and I then knew how big a record I could put in STRING. In V12, L is now one, the length of one element of STRING.

My question is this: Is there anyway with Fortran 2003 to allocate such a character string of a programatically deetermined length, pass it to a subroutine which determines it's length, and fills it without reallocating it with each read? Is there any way to allocate a character variable that doesn't get reallocated all the time?
0 Kudos
18 Replies
IanH
Honored Contributor III
2,162 Views
I'm not sure what you mean by "reallocating it with each read". What/When/How are you reading?

Do you mean like...

[fortran]  CHARACTER(:), ALLOCATABLE :: string
  INTEGER :: LRECL
  LRECL = programmatically_determined_length()
  ALLOCATE(CHARACTER(LRECL):: string)
  CALL a_subroutine(string)
  
  !...

  SUBROUTINE a_subroutine(record)
    CHARACTER(*), INTENT(OUT) :: record
    INTEGER :: i
    !****
    DO i = 1, LEN(record)
      record(i:i) = ACHAR(MOD(i-1,26)+IACHAR('A'))
    END DO
  END SUBROUTINE a_subroutine
[/fortran]
0 Kudos
nvaneck
New Contributor I
2,162 Views
I'm thinking allocated character variables get reallocated every time they are filled, even when passed downand with bounds checking on for debugging it causes problems.The relevant part of the actual routine is:


READ(DCB%HANDLE,'(A)',SIZE=VLEN,IOSTAT=IO_STATUS,ADVANCE='NO') BUFFER

IF (IS_IOSTAT_END (IO_STATUS)) THEN

EOF=.TRUE.

VLEN=0

ELSEIF (VLEN .GT. 0) THEN

RECORD(1:MIN(L,VLEN))=BUFFER(1:VLEN)

ENDIF

So it reads into a static buffer, then fills record, up to the length of the allocated record; L is as mentioned previously, from L=LEN_TRIM(RECORD). My concernis that RECORD remain at a fixed allocation as passed down to the routine and not thrash around with reallocation when reading, e.g., 100,000 records. I think I can allocate a character array and pass the length separately, but was hoping to still take advantage of the length passed by convention.

Ihave several other places where this is a problem, and calls to this routine where it is not a problem, and I'll haveto do a lot of weedingthem all out to fix this if there is no good answer.

I was thinking allocated character variables would be a boon for me, but in fact they are turning out to be trouble. Before, I could set a pointer to an allocated character 1xn array and get it treated as a character string, but that no longer works either.

0 Kudos
IanH
Honored Contributor III
2,162 Views
If RECORD as a dummy argument isn't allocatable (as per my little snippet) it won't be reallocated. Even if it was allocatable, if it appears on the left hand side of an assignment with a substring reference it does not get reallocated - the substring itself doesn't have the allocatable attribute.

Just replace the DO loop in the a_subroutine procedure in my snippet with your read-into-buffer-and-copy-to-record-code. There will only be one allocation - at the allocate statement. All subsequent calls to a_subroutine will use the same storage. No thrashing. The length of the scalar that was allocate gets passed along automatically too if the corresponding dummy argument is assumed length.

Or are you seeing somethng different?
0 Kudos
jimdempseyatthecove
Honored Contributor III
2,162 Views
>>I then pass it to a subroutine where is is defined as CHARACTER RECORD*(*). Before V12, L=LEN(RECORD) gave me the length of STRING, and I then knew how big a record I could put in STRING. In V12, L is now one, the length of one element of STRING

Try using SIZEOF(RECORD)

Jim Dempsey
0 Kudos
nvaneck
New Contributor I
2,162 Views
Thanks, that 's good to know; I didn't think about the substring aspect. I'll try this.
0 Kudos
Steven_L_Intel1
Employee
2,162 Views
If you have an allocatable, assumed-length character variable, declared with length (:), it gets reallocated on assignment in code where it is declared that way, but if you pass it as an argument to a CHARACTER(*), inside the called routine the length is fixed to whatever it was on entry. Do be aware that if you do something like:

CHARACTER(:), ALLOCATABLE :: STR
ALLOCATE (STR(100))
STR = ' '

then STR will, after the assignment, be length 1 not 100.

I would be interested in seeing code that changed behavior in V12. We have fixed some bugs in this area and it could be you were depending on buggy behavior. Or we may have introduced a bug.
0 Kudos
nvaneck
New Contributor I
2,162 Views
Thanks, Steve,

When the allocated string is in a module, I assume it changes whenever used, so one can't centrally allocate strings for which you don't want the length to change aftger allocation.

I was using V10 before. The main change seems to be the length passed to a subroutine is the element length, not the total length. I can't verify this anymore, not having V10 available, but that's where I ran into problems.

Another difference is that you can't allocate a 1 x n string array, and define a pointer to it as a character variable, which worked in F95:

CHARACTER,ALLOCATABLE,TARGET:: S1(:),S2(:),S3(:)
CHARACTER(5000),POINTER:: BOUNDS,RESTRICT,ESTIMATES
ALLOCATE (S1(5000),S2(5000),S3(5000))
BOUNDS=>S1(1);RESTRICT=>S2(1);ESTIMATES=>S3(1)

Bounds checking now works for string length, which didn't happen before.

The rest of the trouble involves my trying to figure out how string allocation works in F2003, which you've cleared up for me; thanks!. Things now seem to make sense wrt the F2003 standard; I just have to check everything carefully and test exhaustively sofware that was stable and ran correctly under V10.
0 Kudos
Steven_L_Intel1
Employee
2,162 Views
You're talking about two very different things here. If you are allocating an array of one-byte characters, the passed length is that of a single element, or 1. If you use the F2003 feature of deferred-length allocatable characters, it should pass whatever the current length is.

I'm a bit puzzled at the compiler's response to the code you posted in your last reply - I'll look into that.
0 Kudos
nvaneck
New Contributor I
2,162 Views
Ok, could it be that the previous compiler did not complain about a string dimensioned longer than the actual sent to the routine, but now does?
0 Kudos
Steven_L_Intel1
Employee
2,162 Views
Oh, yes, definitely it does that now as that is an error and could lead to referencing uninitialized data.
0 Kudos
nvaneck
New Contributor I
2,162 Views
No, I meant that the sent string was shorter than the argument dimensioned in the subroutine and was not filled longer than the actual sent string, so no unitialized data storage was referenced. The error message one gets now complains the lengths do not match, when first referenced, regardless of the length of the data placed in it.

0 Kudos
Steven_L_Intel1
Employee
2,162 Views
Can you show me a short example of what you think should be allowed? What I think yoiu have is something like this:

[fortran]character(10) str
str = 'abcdefghij'
call sub (str)
...
subroutine sub (arg)
character(100) arg
...[/fortran]
This is not legal.
0 Kudos
nvaneck
New Contributor I
2,162 Views
Actually, I meant it complains now if there is not an exact match of length when referenced. What I saw was a complaint when atempting to fill the first 23 bytes of a string of 5000 characters passed down to a routine where the argument in the subroutine was dimensioned much larger (32767). No reference of uninitialized data. This surprised me, but I got around it.

Interestingly enough, it seems if you pass a character array down and dimension it as it's exact lenght, e.g., string*length, it gets by the check of the hidden lenght of 1.

I don't think anything needs to be legal that isn't. Just a learning experience for me about character variables, especially dynamic ones, as things that worked (e.g., as character arrays) before or got passed checking didn't with the new compiler. I think I've got all my code compliant now.

0 Kudos
Steven_L_Intel1
Employee
2,162 Views
Please show me an example of code you think should work but doesn't. There is no requirement that the lengths be an exact match.
0 Kudos
nvaneck
New Contributor I
2,162 Views

How do you delete a reply? I can only manage to edit one edit one....

0 Kudos
Steven_L_Intel1
Employee
2,162 Views
I thought there would be a Delete link for all your posts, but maybe not if there has been a reply. I deleted the first one that you seemed to rewrite. I would still like to see an example of code you think should work but doesn't.
0 Kudos
MWind2
New Contributor III
2,162 Views

What version began to support'CHARACTER(:), ALLOCATABLE :: string'. F 10.0.25 complains about a syntax error, or is the error something else?

0 Kudos
Steven_L_Intel1
Employee
2,162 Views
Version 11.1 was the first to support that F2003 feature.
0 Kudos
Reply