суббота, 26 января 2013 г.

Cовместное использование языков Си и Фортран.

В UNIX системах языки Си и Фортран могут использоваться вместе, так как между этими языками возможны прямые вызовы функций. При этом, правда, необходимо тщательно учитывать совместимость типов передаваемых аргументов. Обычно соответствие между типами в Си и Фортране можно представить так:
signed char    INTEGER*1
short               INTEGER*2
int                   INTEGER
long                INTEGER*4
float                REAL
double            DOUBLE PRECISION
void sub_        SUBROUTINE SUB()
float  fun_()     REAL FUNCTION FUN
Также следует помнить о следующем: 
  • в Фортране аргументы в функции всегда передаются ссылками;
  • В Си массивы передаются через адрес;
  • Порядок индексации многомерных массивов различен для Си и Фортрана - в Си элементы массива располагаются построчно, в Фортране - по столбцам;
  • Имена функций в Фортране имеют в своем конце "скрытый" знак подчеркивания '_' (его нет в исходном тексте, но он добавляется компилятором), поэтому, если некая фунция вызывается из Фортрана как fun(), то эта же функция из Си вызывается как fun_() ; 
  • В языке Си длина строки определяется положением нулевого байта, в Фортране же строки имеют фиксированную длину. Поэтому при передаче строки из Си кода в Фортран необходимо передавать также ее длину. В случае же передачи строки из Фортран кода в Си необходимо добавить нуль в конец строки;
Рассмотрим два случая: когда си код вызывается из фортрана и , наоборот, когда из фортран кода вызывается си код.
Файл cCode1.c:
#include<stdio.h>
void
c_function_(){
     printf("Hello from C code!\n");
}
 Файл fortranCode1.f90:
program hello
    implicit none
    call c_function()
    write (*,*)"Hello from FORTRAN code!"
end program hello
 Компилируем и запускаем на выполнение:
#gfortran -O2 -g -o fortranCode1.o -c fortranCode1.f90
#gcc -O2 -g -o cCode1.o -c cCode1.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode1.o cCode1.o -o hello1
#./hello1
Нужно, чтобы присутствовала библиотека libgfortran.so
 /usr/lib/gcc/i486-linux-gnu/4.7/ - это путь, по которомуона у меня лежит. У вас может быть другой путь.
Обратный случай:
Файл cCode2.c:
#include<stdio.h>
void
main(){
     fortran_function_();
     printf("Hello from C code!\n");
Файл fortranCode2.f90:
subroutine fortran_function
    implicit none
    write (*,*)"Hello from FORTRAN code!"
end subroutine fortran_function
Компилируем и запускаем на выполнение:
#gfortran -O2 -g -o fortranCode2.o -c fortranCode2.f90
#gcc -O2 -g -o cCode2.o -c cCode2.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode2.o cCode2.o -o hello2
#./hello2
Теперь сделаем вызов функции с передачей параметров разных типов.
Файл cCode3.c:
#include<stdio.h>
void
c_function_(signed char* a1, short* a2, int* a3, long int* a4){
     printf("in called c function: \n%d\t%d\t%d\t%ld\n", *a1, *a2, *a3, *a4);
}
 Файл fortranCode3.f90:
program hello
    implicit none
    integer*1 a1
    integer*2 a2
    integer*4 a3
    integer*8 a4
    a1=1
    a2=22
    a3=333
    a4=4444
    call c_function(a1, a2, a3, a4)
end program hello
 #gfortran -O2 -g -o fortranCode3.o -c fortranCode3.f90
#gcc -O2 -g -o cCode3.o -c cCode3.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode3.o cCode3.o -o hello3
#./hello3
 Файл cCode4.c:
#include<stdio.h>
void
main(){
     signed char a1 = 1;
     short            a2 = 22;
     int                 a3 = 333;
     long              a4 = 4444;
     fortran_function_(&a1, &a2, &a3, &a4);
Файл fortranCode4.f90:
subroutine fortran_function(f1, f2, f3, f4)
    implicit none
    integer*1 f1
    integer*2 f2
    integer*4 f3
    integer*4 f4
    write (*,100)f1,f2,f3,f4
100 format(4i5)
end subroutine fortran_function
#gfortran -O2 -g -o fortranCode4.o -c fortranCode4.f90
#gcc -O2 -g -o cCode4.o -c cCode4.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode4.o cCode4.o -o hello4
#./hello4
Теперь продемонстрируем передачу символьных строк из Си в Фортран и обратно.

Файл cCode5.c:
#include<stdio.h>
void
     c_function_(char* string){
     printf("%s\n", string);
}
 Файл fortranCode5.f90:
program hello
    implicit none
    character*37 string
    string="Created in fortran, outputed from C!"
    string(37:37)=char(0)
    call c_function(string)
end program hello
#gfortran -O2 -g -o fortranCode5.o -c fortranCode5.f90
#gcc -O2 -g -o cCode5.o -c cCode5.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode5.o cCode5.o -o hello5
#./hello5 
Теперь наоборот. Сформируем строку в Си, а напечатаем в Фортране.
Файл cCode6.c:
#include<string.h>
void
main(){
     char string[37];
     int length = sizeof(string);
     strncpy(string, "Created in C, outputed from Fortran!", length);
     fortran_function_(string, &length);
}
Файл fortranCode6.f90:
subroutine fortran_function(string, length)
    implicit none
    character*(*) string
    integer length
    write(*,100)string(1:length)
100 format(a)
    return
end subroutine fortran_function
#gfortran -O2 -g -o fortranCode6.o -c fortranCode6.f90
#gcc -O2 -g -o cCode6.o -c cCode6.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode6.o cCode6.o -o hello6
#./hello6
Все примеры протестированы в Debian Wheezy.

1 комментарий:

Unknown комментирует...

Не работает
undefined reference to `basefor1_'