Silverfrost Forums

Welcome to our forums

Transfer function

21 Apr 2010 1:16 #6316

I am converting an FTN77 program to FTN95. The old program has a number of places where characters are assigned to integer values.

When I try to compile these subroutines, I get a statement saying that to solve the error I should use the transfer function. I have tried the function, but it also generated an error saying that I cannot change a character array into a scaler value.

Can you provide an example of using this function.

Thank you.

Michael

22 Apr 2010 12:21 #6319

You could use the intrinsic functions CHAR and ICHAR. Depending on the packing style of the pre f77 program, there may be more than 1 character to an integer array. Reading and writing to an integer2 array with A1 and A2 formats was commonly used and I think still is permitted. I'm surprised that you can not still do that, although it is a much better solution to use character variables and arrays for character data, as they have more implied attributes. The example below uses an integer1 array to store the character data, but you could also use an I2 or I4 array, with less packing density. I've also tested using A2 to store characters into an I*2 array, using a read statement. It still works! but I would not recommend the approach. The problem with old style ftn programs is that they tended to mix both integer and character in the same arrays. Fortran 90+ now provides TYPE structures to define mixed data in an array structure.

      integer*4 ic, n, i, i1, i2
      integer*2 ib(10)
      integer*1 i_char(20)
      character cc*20, bb*20, c
!
      cc = 'abcdefghijklmnopqrst'
!
      n = len (cc)
      do i = 1, n
        ic = ichar (cc(i:i))
        i_char(i) = ic
        write (*,1001) i, cc(i:i), ic, i_char(i)
      end do   
1001  format (i4,a4,2i5)
!
      bb = ' '
      do i = 1,n
         bb(i:i) = char (i_char(i))
      end do
      write (*,*) cc
      write (*,*) bb
!
      read (bb,'(10a2)') ib
      do i = 1,10
         i1 = mod(ib(i),256)
         i2 = ib(i) / 256
         write (*,'(i4,i6,2a2)') i, ib(i), char(i1), char(i2)
      end do
!
      end
22 Apr 2010 12:34 #6326

My problem is that in a lot of cases the integer values are stored in a common. So I would have to go hunt down all the locations to see how the variable is used. In some cases I think they are used as characters, but in other cases I believe that the integer is actually used.

The asignments are things like this.

Integer*4 A

A = 'abcd'

I am trying to create portable code by compiling in FTN95 with the /ISO option. This way was we move forward if the corporate level decides they want to try different compilers I will not have to worrry about having to rewrite much code.

Thanks.

Michael

23 Apr 2010 2:38 #6328

I think your problem is that the program you have is not ISO compliant.

Mixing characters in integer variables is pre F77 and I have removed this use out of most programs I have. It stays in some very old 1970's programs that I don't use frequently enough to bother.

You are right in saying that 'I would have to go hunt down all the locations to see how the variable is used'. You will have to do this !!

The best solution is to locate how these character values are used and then replace the variable with a new character variable. Usually the character value is in part of the integer array in common and is consistently used as character. If the programmer has mixed the values as integer and character, it is more difficult, but then the extent for which they are character or integer should be for that part of the calculation that they relate.

Back in 70's the mixing of real, integer and character in the same array was to save on storage and in some cases with the final size of the required array not known (not defined explicitly in common in this case). In this case, you need a multiple pass of the data to define the problem size then use separate arrays for integer, real and character. A lot of these techniques were based on sharing memory, which is not necessary today. ALLOCATE is a more elegant solution, once the problem size is known.

The answer you don't want, and that I recommend, is go through all uses of this variable/array in your program and replace the character usage with a character variable. A good editer/IDE can quickly find this. Even the DOS command: find /i/n 'variable' *.f95 > variable.tce : will quickly find what you need. (assuming variables don't continue over column 72!) Also all common block definitions should be in include files (using /implicit_none). If the COMMON definition is different in different routines, then the previous programmer has left you a challenge !!

My preferred solution is to try and replace the common by modules and replace the mixed arrays by TYPE structures, although as I've found recently some old techniques, such as use of EQUIVALENCE are difficult to emulate.

On the other hand, what you have should work, with appropriate compiler options, as it did before. But that means it will be difficult to develop this program further to make it look more like a modern program.

All you need is a quite room, away from distractions and a bit of time. Selective global replace can do a lot very quickly.

Good Luck

Please login to reply.