Problems with real array holding character strings

Problems with real array holding character strings

I have a very large, vendor-supplied FORTRAN program that uses a REAL array to hold character strings that are passed back and forth between routines.

VSF 6.6B compiler/linker gives me weird behavior depending on whether the subrotines are in the same source file or different source files. I have created a simple test source below to show the problems:

(1) If the subroutines are together in the same source file, I get an extraneous warning message:
Warning: Routine GETCHARACTER called with different number and/or type of actual arguments in earlier call - C attribute required if intended. Call GetCharacter(XS)

Otherwise the source compiles, links and runs fine.

(2) If the subroutines are in separate source files, the code will not link:

error LNK2001: unresolved external symbol _GETCHARACTER@4

Here is my simple source example you can try in the same file and then separate files.

Thanks
Shawn

Program RealHoldsCharacter
Real XS(20)
Call GetCharacter(XS)
Write(*,*) 'XS= ',XS
Stop
End

Subroutine GetCharacter(AXS)
Character*8 AXS(10)
DO I = 1, 10
AXS(I)=CHAR(I+64)
WRITE(*,*) 'AXS(I)= ',AXS(I)
ENDDO
RETURN
END

13 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

Well, argument-type mismatching has never been part of the Standard since F77, thus the CVF is right to complain that the code is, oh well, broken. Since you probably don't intend to fix it, try compiling it with /iface:cref (Project/Settings/Fortran/External Procedures/Argument Passing/C, by Reference) and prey. You might still (righteously) get the warnings, but you can switch them off in Compilation Diagnostics/Argument Mismatch.

HTH
Jugoslav

Heh, I just love stuff like this... Using /iface:cref may do unwanted things to other parts of your code depending on its structure (thus Jugoslav's recommendation to pray). You could also modify the subroutine a tad to use a byte array, such as:

Subroutine GetCharacter(AXS)
BYTE AXS(80)
AXS = 32
DO I = 1, 10
AXS(I*8-7)=I+64
WRITE(*,*) 'AXS(I)= ',CHAR(AXS(I*8-7))
ENDDO
RETURN
END

James

Thanks for the replies.

Elementyl, the actual vendor coding is too complicated for me to want to use a byte array. And you and Jugoslavdujic are right, the the /iface:cref does unwanted things to the code. Interestingly, the option removes the warning and error messages so that everything compiles and links fine. But it messes up the vendor code execution.

Jugoslavdujic, I already had argument type mismatch checking turned off. With it on, I get

together.f(3) : Warning: In the call to GETCHARACTER, actual argument #1 does not match the type and kind of the corresponding dummy argument.
Call GetCharacter(XS)
--------------------------^
together.f(3) : Warning: In the call to GETCHARACTER, there is no actual argument corresponding to the dummy argument .T4_.
Call GetCharacter(XS)
-------------^
together.f(3) : Warning: Routine GETCHARACTER called with different number and/or type of actual arguments in earlier call - C attribute required if intended.
Call GetCharacter(XS)
-------------^

The first warning shows the mismatch, the 2nd I think is related to FORTRAN passing character lenghths along with string args, and the 3rd is the warning I mentioned in my original note.

With argument-type mismatch checking turned off, I still get that 3rd warning message (but only if they are in the same source file). If they are in different source files, I don't get the warning; but the linker can't find the subroutine (error message I shared in original post).

So, why do I get different warning or error messages if the routines are in different files or not? And why does the linking work if they are in the same file, but not if they are in separate files? Strange.

Thanks for the help,
Shawn

You wrote:

> the actual vendor coding is too complicated for me
> to want to use a byte array.

Now I don't believe that... Anyhow if you don't want to mess with the vendor subroutine, then rename it and create your own subroutine of the same name that uses a byte array and simply copies to and from character variable, then call the vendor subroutine. That should be pretty straightforward to implement.

James

Thanks again for the reply. I really apppreciate your time and ideas.

To get the code to work, all I have to do is combine the offending routines into one source (.F) file. That's what so confusing?????

Like my simple example works between routines in the same source file; but if the routines are in different files the linker complains the subroutine is an unresolved external symbol.

>> the actual vendor coding is too complicated for me
>> to want to use a byte array.

>Now I don't believe that...

Really, it's a maintenance issue. The code is over 170,000 lines long in more than 950 routines dispersed over 230+ source files (not counting 200+ header/include files for common blocks). It is used now on an IBM RS/6000. I would rather not make big changes between the PC and UNIX workstation if I can help it.

The code makes many of these real to character passes between subroutines. The only ones that give me the linking error are located in different source files. Its strange, but try my simple example of both routines in the same source file, then the routines in separate source files.

Thanks again,
Shawn

If you are talking about compiling with the /iface:c switch it should not make any difference, separate or together. Without that switch, the difference is the caller is implicitly given an interface definition for the subroutine, thus it would understand that there should be two arguments, the string address and the hidden length. When compiled separately, the caller assumes the subroutine takes one argument, resulting in a link error when the separately compiled subroutine doesn't cooperate and expects two arguments.

As far as maintaining this code, this really isn't that big, and besides, you want it to work properly and compile cleanly, right? Whenever code plays these sorts of games you are going to make a compromise somewhere. I would simply suggest that you place some conditional compilation (or just use a portable data type in the formal parameter definition) at the top of the vendor subroutine, if compiling for Win32 then create a wrapper routine as I described and have it call the unmodified vendor subroutine, just renamed, should be minimal maintance, you won't have to worry about compilation options or things working. Up to you of course. :-)

James

As far as maintaining this code, this really isn't that big,

Then, what does constitute a big code for you James? ;-)

As you said, /iface:cref shouldn't produce side effects, but I don't think that it is necessarily true for broken codes like this one. But I don't recall if /iface:cref also implies /iface:nomixed_str_len_arg (string length after all arguments). These two in combination are IMO supposed to fix the problem.

Jugoslav

As far as "big" code, I worked on a suite of programs for x-ray crystallography research that at the time exceeded a million lines. That was my introduction to Fortran. :-) No doubt it is still in use and growing today. Regardless, it is always important to stay optimistic!

James

/iface:cref does not imply /iface:nomixed_str_len_arg. Specify both if you have buggy code that deliberately mismatches string and numeric types in calls.

Steve

Retired 12/31/2016

Thanks for all the replies and help!! Bottom line is /iface:cref and /iface:nomixed_str_len_arg fixed my problems. The code compiles and links without warnings or errors.

Some bumps along the road that might help others:
1. Using portability routine without USE DFPORT showed up a problem only after I switched these options.
2. I had to "clean" and "rebuild all" to get rid of the quirky behavior I mentioned in an earlier post when I first tried these options.
3. Steve is right, the cref option does not imply the nomixed_str_len_arg argument. I proved that the hard way, although I thought passing arguments like C, by reference would remove the hidden character lenghths passed by FORTRAN.

Thanks again,
Shawn

Shawn,

You should also complain to your vendor that their code
is not valid Fortran and ask for a possible compensation. Passing a double precision array to a character array
is just plain silly. Sloppy programming like this is
unacceptable.

Regards,

Jean Vezina

Can't you use equivalence?
This will run without any problem.

Program RealHoldsCharacter
Real XS(20)
Character(8) AXS
Equivalence (XS,AXS)
Call GetCharacter(AXS)
Write(*,*) 'XS= ',XS
Stop
End

Subroutine GetCharacter(AXS)
Character*8 AXS(10)
DO I = 1, 10
AXS(I)=CHAR(I+64)
WRITE(*,*) 'AXS(I)= ',AXS(I)
ENDDO
RETURN
END

Walter

Leave a Comment

Please sign in to add a comment. Not a member? Join today