Convert block data F77 to F90 - fortran

I'm converting some F77 files to F90. However, there are some common blocks that did not converted. I'm a novice in F90 and have no experience in F77.
Could someone show me how to covert the following example code to F90?
BLOCK DATA SETUP
INTEGER A,B,C
REAL I,J,K,L
COMMON /AREA1/ A,B,C
COMMON /AREA2/ I,J,K,L
DATA A,B,C,I,J,K,L/0,1,2,10.0,-20.0,30.0,-40.0/
END
My idea is to put the arrays A, B, and C in a module. The main thing I don't get here is the AREA1 and AREA2. How are these used in F77 and how do I translate those? My first guess is to discard them and simply define A,B, & C in the module. However, are they a kind of derive type within which A, B, & C are contained?

First up, the original code should compile in Fortran 90 and later. So if it isn't broken, don't try to fix it.
COMMON blocks are basically global variables. In every procedure that the global variables are used, they have to be declared in the same way1, and then they are shared everywhere. Something like this:
integer a, b
common /globals/ a, b
A more modern approach would be to convert globals into a module:
module globals
implicit none
integer a, b
end module globals
And then use that module everywhere you need access to a and b
program main
use globals
implicit none
a = 4
b = 2
end program main
You could either put the DATA statement into the module, or, even easier, initialise every variable in the declaration:
module AREA1
implicit none
integer :: a = 0
integer :: b = 1
integer :: c = 2
end module AREA1
module AREA2
implicit none
real :: i = 10.0
real :: j = -20.0
real :: k = 30.0
real :: l = -40.0
end module AREA2
Then, you can replace the whole thing by just use AREA1 and use AREA2 before the implicit none everywhere you need access to their variables.
Edit: Forgot the footnote
1The rules for common blocks are more flexible, in that the values for the different variables are stored in a common memory location, in the order that they are named. So while it is not technically necessary to always use the same COMMON statement, you can very easily introduce bugs if you don't.
If you have differently named variables (but of the same type), then adapting that is not that hard. Say you have
integer a, b
common /globals/ a, b
in the main program and
integer i, j
common /globals/ i, j
in a subroutine. Assuming that you create a module with a and b, you can then in the subroutine use it in this way:
use globals, only: i => a, j => b
(Note that if you use only, you have to list every variable that you want to use out of the module. You could use something like: only: a, i => b if you want a and i.)
Of course, the following would also be compatible with the previous globals common block, but might lead to more trouble:
integer k(2)
common /globals/ k

Related

Why do I have to specify implicitly for a double precision return value of a function in Fortran?

I am new to Fortran and I am trying on the common block. My code is simple
program main
implicit double precision (p)
real * 8 :: x, y
common /yvalue/ y
x = 3d0
y = 3d0
print *, power(x)
end program main
function power(x)
implicit none
real * 8 :: power
real * 8 :: x, y
common /yvalue/ y
power = x ** y
end function power
It works but if I comment out the second line, which implicitly declares variables starting with p to be double precision, the compiler complains the following
Error: Return type mismatch of function ‘power’ at (1) (REAL(4)/REAL(8))
I do get the point that the return value power is by default a single precision variable, but why declaring power as double precision in the function is not enough? And why writing real * 8 power in main would not work either?
When a procedure (function or subroutine) that you are trying to invoke in your code lays outside the body of your program and also is not part of any module, it's named an external function (or subroutine).
Fortran is a statically-typed language, so the types of all variables and functions must be known at compile-time. So, if you want to reference an external function in your program, there must be a way for the program to know its return type. You have 3 (bad) options for this, and I'll list them, starting from the worst:
WORST: Rely on an implicit-typing rule that happens to match the return type of the external function with the type associated with its identifier in the caller (as you did in your sample).
Why you shouldn't do that? Because it is cancer. It makes the meaning of the code obscure, you can't know what this name reference to. It may even look just like an array variable in some circumstances, instead of a function. Also, the compiler doesn't check argument conformance in this case, so if you don't have specific compiler options turned on, the code will fail at runtime, or worse, will give wrong results. Moreover, implicit-typing is very very rarely useful these days, most of the time it's an ask for trouble. Always use implicit none!
As you noted, by the default rules of implicit-typing, any variable with a name starting with p will be default real type (in your compiler, it is real(4)). As you declared the function result as real*8, that your compiler interpret as real(8) (see final note), the error arises.
BAD: Declare the function's name and type in the caller's specification area.
You'd do that just like you'd declare a variable, like this:
program main
implicit none
real*8 :: x, y, power
By the way, the attribute external may be applied to external procedures like yours. More than giving some properties to the procedure (can be passed as an actual argument, disambiguation from intrinsic procedures), it would make the origin of the identifier clearer.
program main
implicit none
real*8 :: x, y, power
external :: power
Why you shouldn't do that? There is no argument checking by the compiler either. This severely limits your options for communicating to external functions: the arguments cannot be assumed-shape, assumed-rank, polymorphic, parameterized, coarray, or be declared on the callee side as allocatable, optional, pointer, target, asynchronous, volatile or value; the return type cannot be an array, or pointer, or allocatable; the function cannot be passed as argument, be elemental and, if pure, can't be used in such contexts. And the reason for all this is the lack of an explicit interface.
ACCEPTABLE: Specify an interface for your external function in the caller.
Like this:
program main
implicit none
interface
real*8 function power(y)
real*8 :: y
end function
end interface
This way, the compiler is able to know all details of declaration and all the restrictions I mentioned won't apply. Total freedom and code clarity!
Why you shouldn't do that? Because there is a better way, that is using modules! Well, it's totally ok to do this in contexts were you can't go for modules, e.g. when working with already existent large old code. The downside is that, you have almost the same code in two different places, and they must always match.
Bonus: BETTER: Use modules.
program main
use :: aux_module
implicit none
real*8 :: x, y
common /yvalue/ y
x = 3d0
y = 3d0
print *, power(x)
end
module aux_module
implicit none
contains
function power(x)
real*8 :: power
real*8 :: x, y
common /yvalue/ y
power = x ** y
end
end
Why you should definitely do that? Because with modules, interfaces are automatically and implicitly available (less code duplication, no restrictions); modules can be recompiled separately and updated without breaking code. Also, you can declare shared variables in the scope of the module and avoid using common declarations. An even better version of your code would be:
program main
use aux_module
implicit none
real*8 :: x
x = 3d0
y = 3d0
print *, power(x)
end
module aux_module
implicit none
real*8 :: y
contains
function power(x)
real*8 :: power
real*8 :: x
power = x ** y
end
end
There is even the option to include your functions directly into your program, after contains. This is recommended only if you don't plan to reuse this function in other program units. #IanBush's answer covers this case.
Final note: take a look on this answer to see why the syntax real*8 is non-standard and should be avoided.
As stated in the comments simply declaring the function in not only its own scope but also the scope that it is called will solve your problem. However I also want to discourage you from using common, implicit typing, and the completely non-standard real*8. As such here is a version of your program in a more modern dialect
ian#eris:~/work/stackoverflow$ cat power.f90
Program power_program
Implicit None
Integer, Parameter :: wp = Selected_real_kind( 14, 70 )
Real( wp ) :: x, y
x = 3.0_wp
y = 3.0_wp
! Return type and kind of the function power in scope
! due to the implicit interface
Write( *, '( 3( a, 1x, f0.6, 1x ) )' ) &
'x =', x, 'y = ', y, 'x**y = ', power( x, y )
Contains
Pure Function power( x, y ) Result( r )
Real( wp ) :: r
Real( wp ), Intent( In ) :: x
Real( wp ), Intent( In ) :: y
r = x ** y
End Function power
End Program power_program
ian#eris:~/work/stackoverflow$ gfortran -std=f2003 -Wall -Wextra -O power.f90
ian#eris:~/work/stackoverflow$ ./a.out
x = 3.000000 y = 3.000000 x**y = 27.000000
ian#eris:~/work/stackoverflow$

Fortran reinterpret_cast Equivalent

I have some functions written in Fortran that take a structure as an argument, but the caller has the data stored in an INTEGER*4(2) array. In order to avoid the copy between the two data structures, I'm wondering if the following implementation of a C++-like reinterpret_cast is valid according to the specification:
STRUCTURE /TimeStamp/
INTEGER*4 secondsSinceEpoch
INTEGER*4 nanos
END STRUCTURE
STRUCTURE /reinterpret_cast/
UNION
MAP
INTEGER*4, POINTER :: array(:)
END MAP
MAP
TYPE (TimeStamp), POINTER :: tstamp
END MAP
END UNION
END STRUCTURE
SUBROUTINE set_time(timeArg)
INTEGER*4, TARGET :: timeArg(2)
RECORD /reinterpret_cast/ time
time % array => timeArg
time % tstamp % secondsSinceEpoch = 12
time % tstamp % nanos = 0
END
Is this implementation of the set_time method guaranteed to work (e.g., set the values of timeArg(1) and timeArg(2))?
No, your function is not guaranteed to work by the Fortran standard and many compilers will refuse the syntax altogether. I am not sure whether Fortran pointers are allowed in the DEC structures and if yes, whether you can union them. They (structure and union and record) were designed before Fortran pointers were put into the standard and are strongly discouraged for new code, but it is quite possible Intel allowed Fortran pointers in allowed them.
Much easier (at least for me) way is to use Fortran standard type(c_ptr) which is basically the C void * pointer.
SUBROUTINE set_time(timeArg)
USE, INTRINSIC :: ISO_C_BINDING
INTEGER(c_int_32), TARGET :: timeArg(2)
type(TimeStamp), POINTER :: tstamp
CALL c_f_pointer(c_loc(timeArg), tstamp)
tstamp % secondsSinceEpoch = 12
tstamp % nanos = 0
END
I also changed the INTEGER*4 because it is also not standard conforming and not guaranteed to be C-interoperable.
Do note that the address of the target dummy argument is valid only in the subroutine unless the actual argument is pointer or target.
What you are looking for is the F90-standard function TRANSFER. It interprets the bit representation of the operand as if it was of the same type of another variable (the "mold"). Thus, this:
USE ISO_FORTRAN_ENV ! For the REALnn and INTnn constants
REAL(REAL32) r
INTEGER(INT32) i
r = 1.0
i = TRANSFER(r, i) ! The second "i" here is unevaluated, just gives the type
Is equivalent to this:
float r = 1.0;
int32_t i;
i = *reinterpret_cast<int*>(&f);
Note that the REALnn and INTnn constants are from Fortran 2008, so your compiler might not have them. I just used them as examples to make sure that the types were compatible, since just like in C, the standard does not say precisely how big a "default real" or "default integer" are.
As an example, I frequently use this function when creating Fortran-based MEX functions in Matlab, since the Matlab interface with Fortran is based on F77 and does not allow you to use pointers to Matlab memory directly, unlike the C interface. I use the TRANSFER function and the ISO_C_BINDING module (F2003) to cast the "integer" (actually a C pointer) Matlab gives me to the Fortran type C_PTR, to a Fortran pointer. Like this:
USE ISO_C_BINDING ! For C_PTR and related functions
INTEGER(INT32), POINTER :: arrayPtr(:)
mwSize n ! This is a type defined in the Matlab-Fortran interface
mwPointer myMatlabArray = ... ! So is this
TYPE(C_PTR) cPtrToData
! Cast the returned C pointer to the data (Matlab interface returns an integer type)
cPtrToData = TRANSFER(mxGetData(myMatlabArray), cPtrToData)
! Since Fortran arrays/pointers have size information, get the length
n = mxGetNumberOfElements(myMatlabArray)
CALL C_F_PTR(cPtrToData, arrayPtr, [n]) ! Associate the Fortran ptr
array(3:7) = ... ! Do whatever, no need to copy
Which is the rough equivalent to the C version:
mxArray* myMatlabArray = ...; //
mwSize n = mxGetNumberOfElements(myMatlabArray);
int* arrayPtr = (int*)mxGetData(myMatlabArray);
array[3] = ... // Do whatever, no need to copy
So in both cases these MEX functions could be called with Matlab array of Matlab type int32.

Function type does not match the function definition

I am new to Fortran, writing some practice code with a function that returns Farenheit from Celsius
program Console1
implicit none
real, parameter :: ikind = selected_real_kind(p=15)
real (kind = ikind):: c,f,o,faren
print *, "enter a temperature in degrees celsius"
read *, c
write(*,10) "farenheit =", faren(c)
10 format(a,f10.8)
end program Console1
function faren(c)
real, parameter :: ikind = selected_real_kind(p=15)
real (kind = ikind):: c,f
faren = (9/5)*c + 32
end function faren
I get an error #7977 : The type of the function reference does not match the type of the function definition.
So with that if i change function faren(c) to real function faren(c)
I get the same error, but the types are the same?
Am i missing something? Do I have to define the function in the main program?
There are several issues in addition to the structural/code arrangement ones already noted.
First, KIND is an integer, so you want to change
real, parameter :: ikind = selected_real_kind(p=15)
to
integer, parameter :: ikind = selected_real_kind(p=15)
Ideally, you want to define that in only one place (i.e. in a module) and reference it from both your main program and the function, but the code should be fine as it is for test purposes.
A second issue that often trips up newcomers to Fortran (and Python2) is that real numbers and integers are distinct types and are not generally interchangeable.
faren = (9/5)*c + 32
simplifies to
faren = (1)*c + 32
because integer division has an integer result; 9/5 = 1
Fortran is picky about numerical values (that's sort of the whole point of the language) so what you probably want is:
faren = (9.0 / 5.0) * c + 32.0
Or more precisely, if faren is defined with a specific precision of ikind,
faren = (real(9.0,ikind) / real_(5.0,ikind)) * c + real(32.0,ikind)
or
faren = (9.0_ikind / 5.0_ikind) * c + 32.0_ikind
This syntax tends to make people's heads explode. Welcome to modern fortran ;)
The last issue deals with the horrors of Fortran I/O. From a design standpoint, you need to know what results the user expects and make sure the output format can display them. The legitimate range of input values for c is -273.15 (give or take) to some upper bound which relies on the use case for the code. If you're dealing with cooking temperatures, you probably won't exceed 400.0; if you're doing fusion research, you could be going much higher. Are 8 figures past the decimal useful or believable? In this case, we're just testing the code so we may not need a lot of precision in the output; you'll want to change the output format to something like:
10 format(a,es10.2)
or
10 format(a,g16.8)
You need to ensure the total field width (the number before the dot) can contain the decimal part (the number after the dot) along with the integer part of the number, plus the space needed to show sign and exponent. For scientific notation, four characters are eaten by mantissa sign, decimal point, 'E' and exponent sign. It may be safer just starting out to use an output format of *; it's frustrating to fight with numerics and formatting simultaneously.
That is a good effort and simple start to work through the nuance, so a good question.
Personally I would use reals for the math, rather the 9/5, and use a module. In this example you could pass in a real or a double to C2Faren and the interface/procedure will sort out whether to use the real or the double version. Then you have a few options in case you want different precision.
You could also use the ISO_C_BINDING if you do mixed language...
MODULE MyTEMPS
PRIVATE
DOUBLE PRECISION, PARAMETER :: C2F_ScaleFact = 1.8D0
DOUBLE PRECISION, PARAMETER :: F2C_ScaleFact = /(1.0D0 / 1.8D0)/
DOUBLE PRECISION, PARAMETER :: F2C_Offset = 32.0D0
PUBLIC Faren2C
INTERFACE C2Faren
MODULE PROCEDURE C2Faren_Real, C2Faren_DBL
END INTERFACE
CONTAINS
!========= REAL VERISON =========
REAL FUNCTION C2Faren_Real(c)
IMPLICIT NONE
real, INTENT(IN ) :: c
C2Faren_Real = ( C*F2C_ScaleFact ) + F2C_Offset
RETURN
END FUNCTION C2Faren_Real
!========= DOUBLE VERSION =========
DOUBLE PRECISION FUNCTION C2Faren_DBL(c)
IMPLICIT NONE
DOUBLE PRECISION , INTENT(IN ) :: c
C2Faren_DBL = ( C*F2C_ScaleFact ) + F2C_Offset
RETURN
END FUNCTION C2Faren_DBL
!========= REAL VERSION (Faren to Centigrade) =========
REAL FUNCTION faren2C(Faren)
IMPLICIT NONE
REAL, INTENT(IN ) :: Faren
faren2C = (faren - F2C_Offset) / F2C_ScaleFact
RETURN
END FUNCTION faren2C
END MODULE MyTEMPS
Then your program uses the module via USE n the second line...
program Console1
USE MyTEMPS !<== Here
implicit none
real :: c, f
DOUBLE PRECISION :: Dc, Df ! No way to get Df to C or DC in the module (yet)!
print *, "enter a temperature in degrees celsius"
read *, c
write(*,10) "farenheit =", C2faren(c)
10 format(a,f10.6)
Dc = C
write(*,12) "farenheit =", C2faren(Dc)
12 format("DBL:",A,f10.6)
F = Dc
write(*,14) "Centigrade =", faren2C(F)
14 format("DBL:",A,f10.6)
end program Console1
So/and the main advantage of the module is when you end up wanting to use this stuff in a variety of programs and test and sort out the module once... Usually people put this sort of stuff (lots of modules) in a library, when the module(s) have lot of functions.
You could also put just the real, parameter :: ikind = selected_real_kind(p=15) into a module and use that in both the program and the function and you would be there. You were real close, and it mostly a matter of style and utility.
For Intel Fortran you can use REAL(KIND=4) and REAL(KIND=8)... Which I do, but that is not portable to gfortran, so it is probably a better habit to use the ISO_C_BINDING or just use REAL and DOUBLE PRECISION.
Modules are great but if you have a very simple code another way to work is to put the subroutines and functions in your main program. The trick is to put them after the word contains:
program xxx
stuff
contains
subroutine yyy
function zzz
end program xxx
In this way the functions can see into the contents of the main program so you don't have to re-declare your parameters and you are likely to get more meaningful error messages.
Since you are new I have a great resource I learned a lot from to share:
http://www.uv.es/dogarcar/man/IntrFortran90.pdf

Check values of local variables in subroutines from outside

How do you check values in Fortran like in Matlab? For example in the little program under, why does it show c=0 in main when it is c=36 in the subroutine testing? How do you make it so c=36 in the main program?
Can you call on the value c in some sort of way? I understand that in the main program the variable c is either undefined or has value 0, but is there a way to save the value of c in the subroutine so you can use it again in other subroutines, without calculating it again?
When the program is quite large it is handy to check values as you go.
program main
use test
implicit none
integer :: a,b,c
call testing(a,b)
write(*,*)'Test of c in main program',c
end program main
module test
implicit none
contains
subroutine testing(a,b)
integer :: a,b,c
a=2
b=3
c=(a*b)**a
write(*,*)'Value of c in subroutine',c
end subroutine testing
end module test
It is important to learn about scope in programming languages.
Every name (identifier) has only a limited range of validity.
If you declare some variable inside a subroutine
subroutine s
integer :: i
end subroutine
than the i is valid only in that subroutine.
If you declare a variable in a module
module m
integer :: i
contains
subroutines and functions
end module
then the i is valid inside all those subroutines and functions and also in all program units that use that module.
However, that does not mean that you should declare the variable in the module and just share it. That would be more or less a global variable. This is reserved only for certain cases, where that is necessary, but not for getting results out of your subprograms.
If your subroutine just computes something and you want to get the result of that computation you have two possibilities:
1. pass it as an additional argument, which will be defined by the subroutine
subroutine testing(a, b, c)
integer, intent(in) :: a, b
integer, intent(out) :: c
c = (a*b) ** a
end subroutine
you then call it as
call testing(2, 3, c)
print *, "result is:" c
2. Make it a function
function testing(a, b) result(c)
integer, intent(in) :: a, b
integer :: c
c = (a*b) ** a
end function
and then you can use directly
c = testing(2, 3)
print *, "result is:", c
or just
print *, "result is:", testing(2, 3)
This is the desired behaviour. Basically the calling routine should know nothing about the subroutine except for how to call it and what to get back. This is called encapsulation.
You can make variables accessible to the calling routine by declaring it in the module itself, and not in the subroutine:
module test
implicit none
integer :: c
contains
subroutine testing(a, b)
implicit none
integer :: a, b
a = 2
b = 3
c = (a*b) ** a
write(*, *) "Value of c in the subroutine: ", c
end subroutine testing
end module test
program main
use test
implicit none
integer :: a, b
call testing(a, b)
write(*, *) "Test of c in the main program: ", c
end program main
Note that you must not declare c in the main program, as it will get the variable from the module.
You could also use a COMMON block, but modules are far superior.

Allocating memory in C for a Fortran allocatable

We are trying to take over the memory allocation of a legacy Fortran code (+100,000 lines of code) in C++, because we are using a C library for partitioning and allocating distributed memory on a cluster. The allocatable variables are defined in modules. When we call subroutines that use these modules the index seems to be wrong (shifted by one). However, if we pass the same argument to another subroutine we get what we expect. The following simple example illustrates the issue:
hello.f95:
MODULE MYMOD
IMPLICIT NONE
INTEGER, ALLOCATABLE, DIMENSION(:) :: A
SAVE
END MODULE
SUBROUTINE TEST(A)
IMPLICIT NONE
INTEGER A(*)
PRINT *,"A(1): ",A(1)
PRINT *,"A(2): ",A(2)
END
SUBROUTINE HELLO()
USE MYMOD
IMPLICIT NONE
PRINT *,"A(1): ",A(1)
PRINT *,"A(2): ",A(2)
CALL TEST(A)
end SUBROUTINE HELLO
main.cpp
extern "C" int* __mymod_MOD_a; // Name depends on compiler
extern "C" void hello_(); // Name depends on compiler
int main(int args, char** argv)
{
__mymod_MOD_a = new int[10];
for(int i=0; i<10; ++i) __mymod_MOD_a[i] = i;
hello_();
return 0;
}
We are compiling with:
gfortran -c hello.f95; c++ -c main.cpp; c++ main.o hello.o -o main -lgfortran;
Output from running ./main is
A(1): 1
A(2): 2
A(1): 0
A(2): 1
As you can see the output of A is different, though both subroutines printed A(1) and A(2). Thus, it seems that HELLO starts from A(0) and not A(1). This is probably due to that ALLOCATE has never been called directly in Fortran so that it is not aware of the bounds of A. Any work arounds?
The ISO_C_BINDING "equivalent" code:
c++ code:
extern "C" int size;
extern "C" int* c_a;
extern "C" void hello();
int main(int args, char** argv)
{
size = 10;
c_a = new int[size];
for(int i=0; i<size; ++i) c_a[i] = i;
hello();
return 0;
}
fortran code:
MODULE MYMOD
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
INTEGER, BIND(C) :: SIZE
TYPE (C_PTR), BIND(C) :: C_A
INTEGER(C_INT), POINTER :: A(:)
SAVE
END MODULE
SUBROUTINE TEST(A)
IMPLICIT NONE
INTEGER A(*)
PRINT *,"A(1): ",A(1)
PRINT *,"A(2): ",A(2)
END
SUBROUTINE HELLO() BIND(C)
USE, INTRINSIC :: ISO_C_BINDING
USE MYMOD
IMPLICIT NONE
CALL C_F_POINTER(C_A,A,(/SIZE/))
PRINT *,"A(1): ",A(1)
PRINT *,"A(2): ",A(2)
CALL TEST(A)
END SUBROUTINE
Output:
A(1): 0
A(2): 1
A(1): 0
A(2): 1
Fortran array dummy arguments always start at the lower bound defined in the subroutine. Their lower bound is not retained during the call. Therefore the argument A in TEST() will always start at one. If you wish it to start from 42, you must do:
INTEGER A(42:*)
Regarding the allocation, you are playing with fire. It is much better to use Fortran pointers for this.
integer, pointer :: A(:)
You can then set the array to point to a C buffer by
use iso_c_binding
call c_f_pointer(c_ptr, a, [the dimensions of the array])
where c_ptr is of type(c_ptr), interoperable with void *, which also comes from iso_c_binding.
---Edit---
Once I see that #Max la Cour Christensen implemented what I sketched above, I see I misunderstood the output of your code. The descriptor was indeed wrong, though I didn't write anything plain wrong. The solution above still applies.
The internal representation of fortran arrays is very different than the one used in C/C++.
Fortran uses descriptors that start with a pointer to the array data, and followed by element type size, number of dimensions, some padding bytes, an internal 32/64 bit byte sequence indicating various flags such as pointer, target, allocatable, can be deallocated, etc. Most of these flags are not documented (at least in ifort that I have worked with), and at the end is a sequence of records, each describing the number of elements in the corresponding dimension, distance between elements, etc.
To 'see' an externally created array from fortran, you'd need to create such descriptors in C/C++, but, it does not end there because fortran also makes copies of them in the startup code of each subroutine before it gets to the first one of your statements, depending on indicators like 'in', 'out, 'inout', and other indicators used in the fortran array declaration.
Arrays within a type declared with specific sizes map well (again in ifort) to corresponding C struct members of the same type and number of elements, but pointer and allocatable type members are really descriptors in the type that need to be initialized to the correct values in all their fields so fortran can 'see' the allocatable value. This is at best tricky and dangerous, since the fortran compiler may generate copy code for arrays in undocumented ways for optimization purposes, but it needs to 'see' all the involved fortran code to do so. Anything coming outise of the fortran domain, is not known and can result in unexpected behavior.
Your best bet is to see if gfortran supports something like iso_c_binding and define such interfaces for your fortran code, and then use iso_c_binding intrinsics to map the C_PTR pointers to fortran pointers to types, arrays, etc.
You can also pass a pointer to a one-dimensional array of char, and its size, and this works for strings mostly as long as the size is passed by value as last argument (again, compiler and compiler-flag dependent).
Hope this helps.
EDIT: changed 'ifort's iso_c_binding' to 'iso_c_binding after Vladimir's comment - thanks!