Calling C Language Subprograms from Fortran Programs Kenneth G. Hamilton --- 7-Oct-1998 1. Introduction The Fujitsu C Compiler (FCC) is provided as a part of your LF95 package, as an installation option. There are several examples in this section. The source code, to enable you to experience mixed-language calling, are in subdirectories EXAMPLES\MIXED_LANG\FCC\EX1, EX2, EX3, etc., below your main LF95 directory. Each one is accompanied by a file called GEN.BAT, that will compile and link the sample code. 2. Example 1 --- A Simple Subroutine First, let us look at the simplest example of a Fortran program calling a C subroutine. The following main program defines two integers, I and J, and then calls SUB to add them and return the sum. PROGRAM MAIN integer :: i,j,k i = 12 j = 43 k = 0 print *, 'Before: i,j,k=',i,j,k call sub(i,j,k) print *, 'After: i,j,k=',i,j,k stop end This is the subroutine that performs the addition. void sub_(i,j,k) int *i, *j, *k; { *k = *i + *j; return; } In C, a subroutine is a function of type "void." As we noted earlier, the name of the subroutine must be in lower case letters, with a trailing underscore. Since Fortran normallys passes arguments by reference, the C subroutine must receive them as pointers (hence the "*" in front of the variable names). The type INTEGER variables in Fortran are treated as type "int" in C. 3. Example 2 --- Passing Real Arguments The situation is the same when floaing point arguments are passed. In this example, three default REAL(KIND=4) arguments are sent to a C subroutine, where they are manipulated. PROGRAM FLTMAIN x = 2.17 y = 5.6 z = 0.0 print *,' x,y,z=',x,y,z call cmult(x,y,z) print *,' x,y,z=',x,y,z stop end This is the C subroutine, where the REAL(KIND=4) variables are received as pointers to variables of type "float." If the arguments were REAL(KIND=8), then the C side would expect them as type "double." void cmult_(x,y,z) float *x, *y, *z; { *z = *x * *y + 2.0; return; } 4. Example 3 --- Passing CHARACTER Arguments Passing type CHARACTER variables poses a higher level of complexity. Consider the following main program, which assigns a literal string to A, and then calls CHRCOPY to duplicate A into B. PROGRAM CHRMAIN character*20 a, b a = 'This is a message' b = ' ' print *, 'a=',a print *, 'b=',b call chrcopy(a,b) print *, 'a=',a print *, 'b=',b stop end When LF95 passes type CHARACTER arguments to a subroutine, it actually sends both the starting address of the string, plus the length (which is passed by value). The lengths of any CHARACTER arguments are treated as hidden arguments to the right of the normal argument list. Thus, in the following C subroutine, the argument list consists of four items, even thought we could see only two in the Fortran CALL statement. The first two arguments are the character strings, passed by reference so that they appear here as pointers to variables of type "char." (Type "char" in C is not a true string variable, but is rather a one-byte integer.) The third and fourth arguments are the lengths of A and B, passed by value. We can tell that they are being passed by value here because they are not prefixed by asterisks, but just appear as plain variables. #include void chrcopy_(a,b,na,nb) char *a, *b; int na, nb; { int nmin; nmin = na > nb ? nb : na; strncpy(b,a,nmin); return; } The subroutine first compares the lengths of the two CHARACTER variables, and then selects the minimum (in case they are different). That becomes the number of characters to copy from A to B, and the C library routine "strncpy" is used. 5. Example 4 --- Passing ASCIIZ Arguments In early Fortran compilers, character strings were stored as arrays of numeric storage locations, packed several characters to each word and then terminated by a word or partial word of zero. Because different types of computer have different word lengths, this "Hollerith" scheme often led to seriously nontransportable code. Some computers stored four characters per word, while others stored five, six, eight, or ten characters per word and so many routines that performed input or output required drastic reworking when moved from one brand of computer to another. When the Basic language was released in the 1970s, it introduced the notion of a special "string" data type that was independent of the hardware design. This was such a good idea that it was copied into the 1977 Fortran standard as CHARACTER variables. Unfortunately, at the same time that Fortran was copying from Basic, C was copying from Fortran and so currently C compilers still expect character strings to be stored as an array of numeric storage locations (usually bytes), terminated by a null. In some cases, you may find it preferable to pass CHARACTER variables to C by appending a null, so that it looks like the legacy method expected by the C language. In order to do this, you would change CALL CSUB(...,ASTR,...) into CALL CSUB(...,ASTR//CHAR(0),...) where ASTR is a CHARACTER variable. In this case, however, the Fortran compiler will make a copy of ASTR with the null attached, and pass that. This means that the subroutine will not be able to modify the original string since ASTR//CHAR(0) is an expression rather than a variable, but that may well be desireable. If you want to allow the subroutine to modify the original string, then you should add the null into the CHARACTER variable, as shown in the following example. PROGRAM CHRMAIN character*20 a, b a = 'Original text'//char(0) b = ' ' print *, 'a=',a print *, 'b=',b call chrcaps(a,b) print *, 'a=',a print *, 'b=',b stop end Here is a C subroutine that returns B as a capitalized version of A, as required by the main program. void chrcaps_(a,b,na,nb) char *a, *b; int na, nb; { char *i, *j; for (i = a, j = b; *i != 0; i++, j++) { *j = *i; if (*j >= 97 && *j <= 122) *j -= 32; } return; } In this case, the copying operation is halted by the appearance of a null (the "*i != 0" clause in the "for" statement). Local pointer variables *i and *j are used instead of the ones that were supplied by the caller. 6. Example 5 --- Accessing COMMON Blocks When LF95 processes COMMON blocks, it modifies them in the same way as it does entry points. That is to say that a block named /SAND/ will invisibly become a global object named "_sand_" and this alteration must be dealt with when performing interlanguage calling. The secret name of blank COMMON in "__BLNK__", with two underscores in front and behind. Here is an example of a Fortran main program that supplies values to some variables that are in COMMON blocks, one blank and one named. PROGRAM CMN_MAIN integer :: i real :: x,y,z common /zulu/ x, y common z i = 12 x = 4.5 y = 0.0 z = 8.1 print *, 'Before: i,x,y,z=',i,x,y,z call ccmn(i) print *, 'Before: i,x,y,z=',i,x,y,z stop end That program salls the following C subroutine: extern struct { float x, y; } zulu_; extern struct { float z; } _BLNK__; void ccmn_(i) int *i; { zulu_.y = zulu_.x + (float)(*i); _BLNK__.z += zulu_.x; return; } In order to access the COMMON blocks from C, we must define a pair of structures, and declare them outside of the function body so that they acquire the global attribute and can connect to the COMMON blocks that the Fortran compiler is going to set up. Since C prepends an underscore to the global names, the named common /ZULU/, which is called "_zulu_" in the object modules, must be called "zulu_" (no leading underscore) in the C code. Likewise, the blank COMMON, called "__BLNK__" in the object code, is called "_BLNK__" (only one leading underscore) in C. 7. Example 6 --- Functions Calling a function that is written in C, one that returns a value (as opposed to a subroutine) is fairly simple, as long as you make sure that the type of the function in C matches what Fortran expects to receive. Here is an example of a Fortran main program that calls several C functions, each of a different type. The argument lists are the same for all the functions: two default integers, but the return value differs. PROGRAM MAIN integer :: i,j integer(kind=1) :: k1, i1add integer(kind=2) :: k2, i2add integer(kind=4) :: k4, i4add real(kind=4) :: r4, r4add real(kind=4) :: r8, r8add external :: i1add, i2add, i4add, r4add, r8add ! i = 12 j = 43 k1 = 0; k2 = 0; k4 = 0 print *, 'Before: i,j=',i,j k1 = i1add(i,j) k2 = i2add(i,j) k4 = i4add(i,j) print *, 'After: k1,k2,k4=',k1,k2,k4 r4 = r4add(i,j) r8 = r8add(i,j) print *, 'r4,r8=',r4,r8 ! stop end These are the C functions called by the Fortran main. Note that the type of variable for a function to return is specified in the opening statement, in place of the "void" that was used in the earlier subroutines. char i1add_(i,j) int *i, *j; { char k; k = *i + *j; return(k); } short i2add_(i,j) int *i, *j; { short k; k = *i - *j; return(k); } long i4add_(i,j) int *i, *j; { long k; k = *i * *j; return(k); } float r4add_(i,j) int *i, *j; { float r; r = (float)(*i) + (float)(*j); return(r); } double r8add_(i,j) int *i, *j; { double d; d = (double)(*i) / (double)(*j); return(d); }