CONVEX FORTRAN
_name_
_MAIN__
__name_
где name - имя COMMON блока;
___blnk_
CONVEX C
_name
extern void f_ ( )
extern g_ ( )
#include < stdio.h>
extern void sub1_( );
main()
{
. . . . . . . . . . . . . . . . . . . . . Source file is exc.c
sub1_( ) ;
. . . . . . . . . . . . . . . . . . . . .
}
SUBROUTINE SUB1( )
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . Source file is exf.f
. . . . . . . . . . . . . . . . . . . . .
RETURN
END
Командная строка запуска компилятора
fc -c exf.f
cc exc.c exf.o
Примечание.
В головном модуле exc.c добавляется символ ('_') в конце внешнего имени вызываемого FORTRAN модуля sub1,т.к. компилятор C добавляет символ ('_') в начале имени.
При компиляции исходного FORTRAN модуля SUB1 компилятор FORTRAN добавляет символ ('_') в начало и конец имени.
PROGRAM MAIN Source file is exf.f
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
COMMON A
COMMON /NAMED/ X
CALL SUB1( )
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
END
struct block { double a ; int b ; } ;
void sub1_( ) Source file is exc.c
{
extern struct block __blnk_ ;
extern struct block _named_ ;
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
__blnk_.a = ;
_named_.b = ;
}
Командная строка запуска компилятора
cc -c exc.c
fc -sa exf.f exc.o
Примечание.
В вызываемом модуле exc.c внешние имена именованного (_named_) и неименованного (__blnk_) COMMON блоков содержат на один символ ('_') впереди меньше по сравнению с соглашением об именах компилятора FORTRAN, т.к. компилятор C добавляет ('_') в начале имени. Аналогично и в отношении sub1_.
Таблица 1. Соответствие между типами данных FORTRAN и C.
------------------------------------------------------------------------
N | FORTRAN | C
--|-----------------------------------|---------------------------------
1.|INTEGER*1 X | char x;
|BYTE X |
|LOGICAL*1 X |
| |
2.|INTEGER*2 X | short x;
|LOGICAL*2 X | short int x;
| |
3.|INTEGER X | int x;
|INTEGER*4 X | long x;
|LOGICAL*4 X | long int x;
|LOGICAL X | enum x;
| |
4.|INTEGER*8 X | long long x;
|LOGICAL*8 X | long long int x;
| |
5.|none | unsigned x;
| |
6.|REAL X | float x;
|REAL*4 X |
| |
7.|REAL*8 X | double x;
|DOUBLE PRECISION X | long double x;
| | long float x;
| |
8.|REAL*16 X | none
| |
9.|COMPLEX X | struct{float r,i;} x;
|COMPLEX*8 X |
| |
10|COMPLEX*16 X | struct{double dr,di;} x;
|DOUBLE COMPLEX X |
| |
11|CHARACTER*6 X | char x[7];
| |
12|A(2,3)={ A(1,1),A(2,1),A(1,2), | a[2][3]={a[0][0],a[0][1],
| A(2,2),A(1,3),A(2,3) } | a[0][2],a[1][0],a[1][1],a[1][2]}
| |
13|COMMON /NAMED/ -- named | struct block _named_;
| |
14|COMMON -- unnamed | struct block __blnk_;
| |
-----------------------------------------------------------------------
Примечание.
1. По умолчанию все типы подклассов 1-4 в языке C являются signed.
2. Типы long long, long long int, long float являются расширением ANSI C стандарта и могут быть использованы только с CONVEX C компилятором.
3. Размер текстового массива (строки) в C на единицу превышает количество символов (за счет добавления нулевого элемента).
4. Многомерные массивы в C размещаются по строкам, индексация начинается с 0. Многомерные массивы в FORTRAN размещаются по столбцам, индексация начинается с 1.
CONVEX FORTRAN
Параметры вызываемой программы передаются через ссылку (адрес). Текстовые параметры передают дополнительный аргумент по значению (длину текстовой переменной), который добавляется в конце списка параметров. В случае нескольких текстовых параметров дополнительные аргументы добавляются для каждого из них и располагаются последовательно в конце списка параметров.
COMPLEX*8 FUNCTION CMADD(J1,J2)
INTEGER*4 J1,J2
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
Компилятор FORTRAN транслирует COMPLEX*8 функцию CMADD в подпрограмму CMADD, в которой первый аргумент является адресом возвращаемого функцией значения:
SUBROUTINE CMADD(RET,J1,J2)
INTEGER*4 RET
INTEGER*4 J1,J2
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
RET=%REF(X)
где X - возвращаемое значение.
Функции, возвращающие текстовое значение, добавляют два дополнительных аргумента (адрес текстовой переменной результата и максимальную длину текстовой переменной) перед первым параметром списка.
CHARACTER*5 FUNCTION CADD(J1,J2)
INTEGER J1,J2
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
Компилятор FORTRAN транслирует CHARACTER функцию CADD в программу CADD, в которой первым аргументом является адрес, а вторым длина текстовой переменной возвращаемого значения:
SUBROUTINE CADD(RET,5,J1,J2)
INTEGER*4 RET
INTEGER*4 J1,J2
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
RET=%REF(X)
где X - возвращаемое значение.
CONVEX C
Параметры вызываемой программы передаются по значению,за исключением массивов, которые передаются через ссылку (адрес).
%VAL(arg) - осуществляет передачу параметра arg по значению;
%REF(arg) - осуществляет передачу параметра arg через ссылку.
Аргументами вышеприведенных функций могут быть только фактические параметры из списка вызываемого модуля.
%LOC(arg) - вычисляет адрес аргумента ;
ROW_WISE(arg) - изменяет порядок индексов двумерного массива (на обратный).
Таблица 2. Соответствия типов аргументов встроенных функций.
-----------------------------------------------------------------------
Name | Type of argument | Examples
-----------|----------------------------|------------------------------
%VAL | LOGICAL(*1,2,4) | CALL SUB(3,%VAL(10))
| INTEGER(*1,2,4) | first parameter passed by
| REAL *4 | reference,second by value.
| |
%REF | excluding Hollerith |
| |
%LOC | INTEGER | I=%LOC(J)-4
| (index of array) | adress of the word preceding J
| |
ROW_WISE | name of array | the description
| | DIMENSION A(4,10)
| | is equivalent to :
| | C$DIR ROW_WISE (A)
| | DIMENSION A(10,4)
-----------------------------------------------------------------------
#include < stdio.h> /* Source file is cfir.c */
extern void sub1_( int *integer, float *real );
main()
{
int i = 0;
float a = 0.0;
sub1_(& i,& a);
(void) printf ("%d\n%f\n", i, a );
}
SUBROUTINE SUB1( J, B ) ! Source file is cfir2.f
INTEGER*4 J
REAL*4 B
J=1234567
B = 9876.543
RETURN
END
Строка запуска компилятора
fc -c cfir2.f
cc cfir.c cfir2.o
Результат
i= 1234567
a= 9876.542969
Примечание.
При передаче переменных i, a используется операция взятия адреса & , поскольку в FORTRAN параметры передаются через ссылку. Соответственно в строке описания прототипа sub1_ в головной программе параметры описываются как указатели.
#include < stdio.h> /* Source file is cffunc.c */
extern float addem_(float *al, float *a2);
extern int iaddem_(int *i1,int *i2);
main()
{
int i1 = 43;
int i2 = 12;
float a1 = 43.;
float a2 = 12.;
(void)printf("%d\n",iaddem_(& i1,& i2) );
(void)printf("%f\n", addem_(& a1, & a2) );
}
INTEGER FUNCTION IADDEM ( J1,J2 ) ! Source file is cffunc2.f
INTEGER J1, J2
IADDEM = J1 + J2
RETURN
END
REAL FUNCTION ADDEM(B1, B2)
REAL B1, B2
ADDEM = B1 + B2
RETURN
END
Строка запуска компилятора
fc -c cffunc2.f
cc cffunc.c cffunc2.o
Результат
iadd= 55
add= 55.000000
Примечание.
IADDEM( ), ADDEM( ) - FORTRAN функции, возвращающие сумму двух аргументов.
#include < stdio.h> /* Source file is cfchar.c */
extern void sub1_( char str1[], char str2[], int *arg3,
long len1, long len2 );
main ()
{
char str1[10];
char str2[6];
int num = 4;
sub1_(str1,str2,& num,10,6);
str1[9] = '\0';
str2[5] = '\0';
(void) printf ("%s %s\n",str1,str2);
}
SUBROUTINE SUB1 (CVAR1,CVAR2,CVAR3) ! Source file is cfchar2.f
CHARACTER*10 CVAR1
CHARACTER*6 CVAR2
INTEGER CVAR3
CVAR1 = '123456789'
CVAR2 = 'abcde'
RETURN
END
Строка запуска компилятора
fc -c cfchar2.f
cc cfchar.c cfchar2.o
Результат
str1= 123456789
str2= abcde
Примечание.
В строке описания прототипа sub1_ и в строке обращения содержатся два дополнительных параметра - длины переменных str1, str2, отсутствующие в списке формальных параметров SUB1.
Поскольку FORTRAN автоматически не добавляет символ '\0' в конце строки, необходимо это выполнить в головной программе перед вызовом функции печати printf.
#include < stdio.h> /* Source file is cfcfunc.c */
extern void makestr_(char cstring[], long int cstr_len, char *arg1,
int arg2, long int arg1_len );
main()
{
char cstring[20];
char wxyz[] = " wxyz";
int arg = 60;
makestr_(cstring, 20L,wxyz, arg, sizeof(wxyz) -1 );
(void)printf("%s\n",cstring );
}
CHARACTER*20 FUNCTION MAKESTR (CVAR1,ARG)
CHARACTER*5 CVAR1
INTEGER ARG ! Source file is cfcfunc2.f
MAKESTR = CVAR1// ' edcba'//CHAR(0)
RETURN
END
Строка запуска компилятора
fc -c cfcfunc2.f
cc cfcfunc.c cfcfunc2.o -lf77
Результат
cstring= wxyz edcba
Примечание.
Компилятор FORTRAN транслирует функцию MAKESTR в подпрограмму с именем makestr_, в которой первым аргументом является адрес, а вторым длина возвращаемого текстового значения. Последний аргумент - длина передаваемой текстовой переменной (без элемента '\0').
В MAKESTR используется встроенная функция for$s_cat для операции конкатенации, требующая библиотеки libf77. Поэтому при компоновке используется дополнительная опция -lf77.
#include < stdio.h> /* Source file is cfcmplx.c */
typedef struct{ float r,i;} complex8_t;
typedef struct{ double r,i;} complex16_t;
extern void sub1_( complex8_t *cx1, complex16_t *cx2);
main ( )
{
complex8_t cx1;
complex16_t cx2;
sub1_ (& cx1, & cx2);
(void)printf ("(%f,%f)\n",cx1.r,cx1.i);
(void)printf ("(%f,%f)\n",cx2.r,cx2.i);
}
SUBROUTINE SUB1 (CX1,CX2) ! Source file is cfcmplx2.f
COMPLEX*8 CX1
COMPLEX*16 CX2
CX1 = (1234.0,5678.0)
CX2 = (8765.0,4321.0)
RETURN
END
Строка запуска компилятора
fc -c cfcmplx2.f
cc cfcmplx.c cfcmplx2.o
Результат
cx1= (1234.000000,5678.000000)
cx2= (8765.000000,4321.000000)
#include < stdio.h> /* Source file is cfxfunc.c */
typedef struct {float r, i;} complex8_t;
extern void makecx_( complex8_t *cx, float *a1, float *a2);
main()
{
float a1 = 43.;
float a2 = 12.;
complex8_t cx;
makecx_(& cx,& a1,& a2);
(void)printf("(%f,%f)\n", cx.r, cx.i );
}
COMPLEX FUNCTION MAKECX (B1, B2) ! Source file is cfxfunc2.f
REAL B1,B2
MAKECX = CMPLX (B1*2, B2*2)
RETURN
END
Результат
cx= (86.000000,24.000000)
Примечание.
В строке описания прототипа makecx_ и в строке обращения добавляется дополнительный аргумент (адрес результата) перед первым параметром списка.
Возвращаемое MAKECX значение является структурой. В данном примере используется механизм возврата значений, принятый по умолчанию компилятором C (через сегмент данных памяти).
В данном примере используется новый (стековый) механизм возврата значений. Строка запуска компилятора C включает дополнительную опцию
cc -compat rrf=stack
Данная опция может применяться при компиляции функций С, у которых возвращаемый результат является структурой и передается по значению. Для использования нового механизма возврата значений необходимо ввести в исходный код программы cfxfunc.c изменения. Ниже приводятся модифицированные строки cfxfunc.c из примера 2, а также модифицированный исходный код.
. . . . . . . . . . . . . . . . . . . . . . . . . .
extern complex8_t makecx_(float*a1,float*a2);
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
cx=makecx_(& a1,& a2);
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
#include < stdio.h> /* Source file is cfxfunc1.c */
typedef struct {float r, i;} complex8_t;
extern complex8_t makecx_(float*a1,float*a2);
main()
{
float a1 = 43.;
float a2 = 12.;
complex8_t cx;
cx=makecx_(& a1,& a2);
(void)printf("(%f,%f)\n", cx.r, cx.i );
}
Строка запуска компилятора
fc -c cfxfunc2.f
cc -compat rrf=stack cfxfunc1.c cfxfunc2.o
Результат
cx= (86.000000,24.000000)
#include < stdio.h> /* Source file is cfarr.c */
extern void sub1_( int a[][3] );
main ()
{
int a[5] [3];
int i;
sub1_(a);
for(i=0; i< 5; i++)
(void)printf("%3d %3d %3d\n", a[i][0],a[i][1],a[i][2]);
}
SUBROUTINE SUB1 (A) ! Source file is cfarr2a.f
C$DIR ROW_WISE (A)
INTEGER A(5,3)
DO I = 1,5
DO J = 1,3
A(I,J) = I*J
ENDDO
ENDDO
RETURN
END
SUBROUTINE SUB1 (A) ! Source file is cfarr2b.f
INTEGER A(3,5)
DO J = 1, 5
DO I = 1, 3
A(I,J) = I*J
ENDDO
ENDDO
RETURN
END
Строка запуска компилятора
fc -c cfarr2a.f
fc -c cfarr2b.f
cc cfarr.c cfarr2a.o
Результат
1 2 3
2 4 6
a= 3 6 9
4 8 12
5 10 15
Примечание.
Для согласования разныж способов хранения и индексации массивов в FORTRAN и C ,исходный код FORTRAN программы модифицируется путем включения директивы компилятора ROW_WISE в модуле cfarr2a.f или посредством инверсии индексов массива в модуле cfarr2b.f.
! Source file is fccmn.f
PROGRAM MAIN
REAL*8 A, X
INTEGER*4 B, Y
COMMON A, B
COMMON /NAMED/ X, Y
CALL SUB1 ( )
PRINT *, A, B
PRINT *, X, Y
END
struct block { double a; int b; }; /* Source file is fccmn2.c */
void sub1_( )
{
extern struct block __blnk_;
extern struct block _named_;
__blnk_.a = 3.1415927;
__blnk_.b = 61659;
_named_.a = 2.7182818;
_named_.b = 95616;
}
Строка запуска компилятора
cc -c fccmn2.c
fc fccmn.f fccmn2.o
Результат
A= 3.14159270 B= 61659
X= 2.71828180 Y= 95616
Примечание.
В С именованный и неименованный COMMON блоки представляются структурами с предопределенными именами.
! Source file is fcir.f
PROGRAM MAIN
INTEGER*4 I /0/
REAL*4 A /0.0/
CALL SUB1(I,A)
PRINT *, I,A
END
void sub1_(int *j, float *b) /* Source file is fcir2.c */
{
*j=1234567;
*b=9876.543;
}
Строка запуска компилятора
cc -c fcir2.c
fc -sa fcir.f fcir2.o
Результат
I= 1234567 A= 9876.543
Примечание.
По умолчанию список аргументов FORTRAN программ на этапе компиляции помещается в статическую область памяти программного сегмента. Опция -sa требует помещения списка аргументов в стек. Данная опция используется при вызове С программ из FORTRAN.
Параметры j и b описываются в sub1_ как указатели,т.к. в FORTRAN параметры вызываемой программы передаются через ссылку.
PROGRAM MAIN ! Source file is fcfunc.f
REAL*4 ADDEM, B1 /43.0/, B2 /12.0/
INTEGER*4 IADDEM, J1 /43/, J2 /12/
PRINT *, ADDEM(B1,B2)
PRINT *, IADDEM(J1,J2)
END
float addem_( float *a1, float *a2 ) /* Source file is fcfunc2.c */
{
return( *a1+ *a2 );
}
int iaddem_( int *i1, int *i2 )
{
return( *i1 + *i2 );
}
Строка запуска компилятора
cc -c fcfunc2.c
fc -sa fcfunc.f fcfunc2.o
Результат
ADDEM= 55.00000
IADDEM= 55
PROGRAM MAIN ! Source file is fcfunc1.f
REAL*4 ADDEM,B1/43.0/,B2/12.0/
PRINT *,ADDEM(%VAL(B1),%VAL(B2))
END
float addem_(float a1,float a2) /* Source file is fcfunc3.c */
{
return(a1+a2);
}
Строка запуска компилятора
cc -c fcfunc3.c
fc -sa fcfunc1.f fcfunc3.o
Результат
ADDEM= 55.00000
Примечание.
Пример 6.4 является вариантом примера 6.3. Используется встроенная функция компилятора FORTRAN %VAL для передачи параметров функции ADDEM по значению. Функция %VAL может использоваться только в строке вызова ADDEM со списком фактических параметров.
PROGRAM MAIN ! Source file is fcchar.f
CHARACTER*11 CVAR1 /' '/
CHARACTER*6 CVAR2 /' '/
CALL SUB1 (CVAR1, CVAR2)
PRINT *, CVAR1, CVAR2
END
#include < string.h> /* Source file is fcchar2.c */
void sub1_(char *str1,char *str2,int d1,int d2)
{
(void) strncpy( str1, "1234567890", d1);
(void) strncpy( str2, "abcde", d2);
}
Строка запуска компилятора
cc -c fcchar2.c
fc -sa fcchar.f fcchar2.o
Результат
CVAR1= 1234567890
Примечание.
В описании текстовых переменных CVAR1, CVAR2 в MAIN программе резервируется память для дополнительного символа (конца строки), поскольку при вызове функции sub1_ во время копирования данных в эти переменные дописывается символ конца строки.
Параметры d1, d2 добавляются в конце списка параметров sub1_ в соответствии с соглашениями о передаче текстовых параметров компилятора FORTRAN. Данные параметры передаются по значению и соответствуют декларируемым в MAIN программе длинам CVAR1, CVAR2. Поэтому они не описываются как указатели и компилятор FORTRAN помещает их значения в стек.
PROGRAM MAIN ! Source file is fccfunc.f
INTEGER VAL1, VAL2
CHARACTER*10 DIGITS /'0123456789'/
CHARACTER*30 MAKESTR
PRINT 400, MAKESTR (DIGITS,VAL1,VAL2), VAL1, VAL2
400 FORMAT('String=',A,'|Val1=',I3,'|Val2=',I3,'|')
END
#include < string.h> /* Source file is fccfunc2.c */
void makestr_(char cstr[], long int cstr_len, char *arg1,
long int *num1, long int *num2, int arg1_len )
{
(void) strcpy( cstr, "abcde " );
(void) strcat( cstr, arg1 );
*num1 = cstr_len;
*num2 = arg1_len;
}
Строка запуска компилятора
cc -c fccfunc2.c
fc -sa fccfunc.f fccfunc2.o
Результат
String=abcde 0123456789|Val1= 30|Val2= 10|
Примечание.
В соответствии с соглашениями о передаваемых параметрах компилятор FORTRAN транслирует CHARACTER функцию MAKESTR в подпрограмму,в которой первым аргументом является адрес,а вторым - длина текстовой переменной возвращаемого значения. Функция makestr_ имитирует подпрограмму MAKESTR и имеет тип void. В начале списка параметров makestr_ добавляются два дополнительных аргумента - адрес и максимальная длина текстовой переменной результата. В конце списка параметров также добавляется дополнительный аргумент (длина переменной DIGITS).Второй и последний дополнительные аргументы передаются по значению и соответствуют длинам декларируемых в MAIN программе переменных MAKESTR и DIGITS.
PROGRAM MAIN ! Source file is fccplx.f
COMPLEX*8 CX /(0.0,0.0)/
CALL SUB1 (CX)
PRINT *, CX
END
void sub1_( struct { float r,i;} *cxs ) /* Source file is fccplx2.c */
{
cxs-> r=123.45;
cxs-> i=678.90;
}
Строка запуска компилятора
cc -c fccplx2.c
fc -sa fccplx.f fccplx2.o
Результат
CX = ( 123.4500 , 678.9000 )
PROGRAM MAIN ! Source file is fcxfunc.f
COMPLEX*8 MAKECX8, ANS8
COMPLEX*16 MAKECX16, ANS16
REAL*4 B1 /5.0/, B2 /7.0/
REAL*8 D1 /5.0/, D2 /7.0/
ANS8 = MAKECX8(B1,B2)
ANS16 = MAKECX16(D1,D2)
PRINT *, ANS8
PRINT *, ANS16
END
/* Source file is fcxfunc2.c */
typedef struct {float r, i;} complex8_t;
typedef struct {double r, i;} complex16_t;
void makecx8_( complex8_t *cx, float *a1, float *a2 )
{
cx-> r = *a1 + *a2;
cx-> i = *a1 - *a2;
}
void makecx16_( complex16_t *cx, double *a1, double *a2 )
{
cx-> r = *a1 + *a2;
cx-> i = *a1 - *a2;
}
Строка запуска компилятора
cc -c fcxfunc2.c
fc -sa fcxfunc.f fcxfunc2.o
Результат
ANS8 = ( 12.00000 , -2.000000 )
ANS16 = ( 12.0000000000000 , -2.00000000000000 )
Примечание.
В начало списка параметров функций makecx8_ и makecx16_ добавляется дополнительный аргумент (адрес результата). Возвращаемое makecx8_ и makecx16_ значение является структурой. В данном примере используется механизм возврата значений,принятый по умолчанию компилятором С (через сегмент данныж памяти).
В данном примере используется новый(стековый) механизм возврата значений. Строка запуска компилятора С включает дополнительную опцию:
cc -c -compat rrf=stack fcxfunc3.c
Данная опция может применяться при компиляции функций С, у которых возвращаемый результат является структурой и передается по значению.
Ниже приводится модифицированный исходный код модуля fcxfunc3.c, отличающийся от fcxfunc2.c
/* Source file is fcxfunc3.c */
typedef struct {float r, i;} complex8_t;
typedef struct {double r, i;} complex16_t;
complex8_t makecx8_( float *a1, float *a2 )
{
complex8_t cx;
cx.r = *a1 + *a2;
cx.i = *a1 - *a2;
return cx;
}
complex16_t makecx16_( double *a1, double *a2 )
{
complex16_t cx;
cx.r = *a1 + *a2;
cx.i = *a1 - *a2;
return cx;
}
Результат
ANS8 = ( 12.00000 , -2.000000 )
ANS16 = ( 12.0000000000000 , -2.00000000000000 )
1. CONVEX Interlanguage Programming Guide, First Edition, 1992
2. CONVEX C Guide, Second Edition, 1993
3. CONVEX FORTRAN User's Guide, Tenth Edition, 1992