Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [Interop] Работающий пример iso_c_binding 
V
    Опции темы
popovda
Дата 29.3.2009, 23:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 290
Регистрация: 9.6.2006
Где: Москва

Репутация: нет
Всего: 6



Итак. Пример прост: фортрановская программа вызывает статическую библиотеку на C. Всё сделано в VisualStudio 2003/2005 и Intel Fortran 10.1. По субъективным впечатлениям - g95+gcc работают гораздо удобнее, но оптимизация кода ниже. Да и не родные это для Windows компиляторы. Так что смотрите, кому интересноsmile

Исходник библиотеки
Код

#include <stdio.h>

typedef struct CStruct{
    int a;
    int b;
    char ch;
    double c[10];
} TCStruct;

TCStruct globalS;

void show(int x){
    printf("C: Value = %d\n",x);
}//show

int returnValue(int x){
    printf("C: Value = %d\n",x);
return x;
}

void showArray(const int sz, double Arr[]){
    int i = 0;
    
    printf("sz = %d\n",sz);
    for(i = 0; i<sz; i++){
        printf("C: Arr[%d] = %f\n",i,Arr[i]);
    }
}//showArray

void getStruct(TCStruct *S){
    int l;
    S->a = globalS.a*2;
    S->b = globalS.b*3;
    S->ch = globalS.ch +'0';
    for(l = 0;l<10;l++){
        S->c[l] = globalS.c[l];
    }

    printf("C: Struct is Get with difference\n");
}//getStruct

void setStruct(TCStruct S){
    int l;
    
    printf("C: Struct is set\n");
    
    globalS.a = S.a;
    globalS.b = S.b;
    globalS.ch = S.ch;
    for(l = 0;l<10;l++){
        globalS.c[l] = S.c[l];
    }
}//getStruct


Исходник модуля с интерфейсами к библиотеке
Код

module mod_CInterfaces

use, intrinsic :: iso_c_binding;
implicit none;
! Опишем нашу структуру.
!По-хорошему, все типы и глобальные переменные, которые использует C, надо вынести в отдельный модуль
!Почему, см. код ниже.
type CStructure
    sequence
    
    integer(c_int) :: a;
    integer(c_int) :: b;
    character :: ch;
    real(c_double),dimension(10) :: c;
end type;


interface
    ! Для void show(int x)
    subroutine Show(x) bind(C,name = "show")
        use, intrinsic :: iso_c_binding;
        
        integer(c_int), value, intent(in) :: x;
    end subroutine Show;
    ! Для void showArray(const int sz, double Arr[])
    subroutine ShowArray(sz, Arr) bind(C,name = "showArray")
        use, intrinsic :: iso_c_binding;
        
        integer(c_int), value, intent(in) :: sz;
        type(c_ptr), value, intent(in) :: Arr;
    end subroutine ShowArray;
    ! Для int returnValue(int x)
    integer(c_int) function ReturnValue(x) bind(C,name = "returnValue")
        use, intrinsic :: iso_c_binding;
        
        integer(c_int), value, intent(in) :: x;
    end function ReturnValue;
    ! Для void getStruct(TCStruct *S)
    subroutine GetStruct(S) bind(C,name='getStruct')
        use, intrinsic :: iso_c_binding;
        
        type(c_ptr), value :: S;
    end subroutine GetStruct;
    ! Для void setStruct(TCStruct S)
    subroutine SetStruct(S) bind(C,name='setStruct')
        use, intrinsic :: iso_c_binding;
        implicit none;
        ! Вот почему типы выгоднее выносить в отдельный модуль, чтобы не дублировать код
        type CStructure
            sequence
    
            integer(c_int) :: a;
            integer(c_int) :: b;
            character :: ch;
            real(c_double),dimension(10) :: c;
        end type;
        
        type(CStructure), value, intent(in) :: S;
    end subroutine SetStruct;
end interface;

end module mod_CInterfaces




И сама вызывающая программа
Код

program Test_binding

use mod_CInterfaces;
implicit none;

integer(4), parameter :: sz = 22;

integer(4) :: test_val;
real(8), dimension(:), allocatable :: Arr;

type(CStructure) :: S;

test_val = 10;
! Передача по значению - трудностей нет
call Show(test_val);
print *,'Fortran: test_val = ',test_val;

! Аналогично и с функцией
test_val = ReturnValue(test_val+sz);
print *,'Fortran: test_val = ',test_val;

! Массив. Я просто динамические массивы люблю:)
allocate(Arr(1:sz));
Arr = 100.0;
! Обратите внимание, всё что передается как указатель ДОЛЖНО БЫТЬ передано как указатель
call ShowArray(sz, c_loc(Arr));
deallocate(Arr);

S%a = 10;
S%b = 20;
S%ch = 'a';
S%c = (/1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 0.0/);

! Опять по значению
call SetStruct(S);
! А здесь по указателю
call GetStruct(c_loc(S));

write(*,*) 'Fortran: ',S;

print *,'press ENTER';
read(*,*);
end program Test_binding



P.S. пора бы всё же фортрановский код подсветитьsmile
P.S.S кстати, интересный способ предлагает Silverfrost Fortran для связывания с C. Удобный, но не стандартный. Объявление C_EXTERNAL
Код

C_EXTERNAL FunctionArgumentsValue "_FunctionArgumentsValue" (VAL,VAL)

Например для
Код

extern "C" DllExport void _FunctionArgumentsValue(int i, double x)
{
    printf("%s%d%s%f\n",
        "_FunctionArgumentsValue called with arguments: ",
        i,", ",x);
}

Обратите внимание - результат объявляется по-фортрановски, а в скобках указывается - по ссылке или по значению передавать аргумент.
Довольно удобно.

Это сообщение отредактировал(а) popovda - 15.10.2009, 22:26

Присоединённый файл ( Кол-во скачиваний: 5 )
Присоединённый файл  F_call_C.rar 483,93 Kb


--------------------
С уважением, Попов Д.А.
PM MAIL   Вверх
adejneka
Дата 30.3.2009, 05:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 8.7.2005
Где: Москва, Россия

Репутация: нет
Всего: 11



Интересно, а как компилятор Фортрана определяет, что второй аргумент showArray - это указатель именно на double, а не на что-то другое? Или сейчас это уже не имеет значения?
PM MAIL   Вверх
popovda
Дата 30.3.2009, 07:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 290
Регистрация: 9.6.2006
Где: Москва

Репутация: нет
Всего: 6



Вот это и мне интересноsmile Тем более, что стандарт допускает передачу массива определенной длины в C-функцию не только как type(c_ptr), но и именно как массив, передаваемый по ссылке. Интеловцы, судя по всему, не доработали. Так же похоже, что используется неявное приведение типа. Вроде такой логики компилятора: "раз пользователь передаёт массив типа real(8) в функцию, то ответственность, что в C это именно real(c_double) == double лежит на самом пользователе и на C". Причём, для обратной операции, например получения адреса первого элемента массива, используется функция C_F_POINTER, которая приводит указатель с к указателю Фортрана.

Следует заметить, что в g95 передача массива как массива (естественно, без атрибута value) так же работает. 


--------------------
С уважением, Попов Д.А.
PM MAIL   Вверх
Cr@$h
Дата 30.3.2009, 23:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Исследователь
***


Профиль
Группа: Участник Клуба
Сообщений: 1693
Регистрация: 3.4.2005
Где: Санкт-Петербург, Россия

Репутация: 1
Всего: 41



С другой стороны, что тут кто должен проверять? Интересно, а так сработает:
Код

subroutine ShowArray(sz, Arr) bind(C,name = "showArray")
        use, intrinsic :: iso_c_binding;
        
        integer(c_int), value, intent(in) :: sz;
        type(c_double), value, dimension(*), intent(in) :: Arr;
    end subroutine ShowArray;

call ShowArray(sz, Arr);

Цитата(popovda @  30.3.2009,  08:54 Найти цитируемый пост)
Тем более, что стандарт допускает передачу массива определенной длины в C-функцию не только как type(c_ptr), но и именно как массив, передаваемый по ссылке. 

Тут не вопрос: из описателя Fortran вытаскивается указатель и передаётся в С-функцию.
Цитата(popovda @  30.3.2009,  08:54 Найти цитируемый пост)
Вроде такой логики компилятора: "раз пользователь передаёт массив типа real(8) в функцию, то ответственность, что в C это именно real(c_double) == double лежит на самом пользователе и на C".

Возможно, я не так понял. Если С ловит double и интерфейс на Fortran написан doiuble, то проверять ничего не нужно. А вот если программист ошибется и напишет в Fortran другой тип, то по идее должна срабатывать ошибка при компоновке! Должна. Вся эта информация должна хранится в *.lib.

P.S. Даёшь свободу точкам с запятым! Нечего пленить их к каждой строчке. smile


Это сообщение отредактировал(а) Cr@$h - 30.3.2009, 23:11
PM MAIL ICQ   Вверх
popovda
Дата 1.4.2009, 22:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 290
Регистрация: 9.6.2006
Где: Москва

Репутация: нет
Всего: 6



Да. Вроде бы так. Но с массивом подразумеваемой длины 10-ый интел у меня страшно кочевряжился и не заработал. g95 этот же код съел. Так что я в легком затрудненииsmile 

[code]
! Для void showArray(const int sz, double Arr[])
    subroutine ShowArray(sz, Arr) bind(C,name = "showArray")
        use, intrinsic :: iso_c_binding;
        
        integer(c_int), value, intent(in) :: sz;
        type(c_ptr), value, intent(in) :: Arr;
[\code]

Что до интерфейса - пользователь передаёт в C-функцию указатель type(C_PTR), и это всего лишь указатель, целое число. А целое - оно всегда целое. 

P.S. Точка с запятой - привычка из C. И Ады. Лучше я буду их и фортране ставить - это не вызывает ошибки, чем я буду забывать их ставить в C и тем более Аде. 


--------------------
С уважением, Попов Д.А.
PM MAIL   Вверх
adejneka
Дата 2.4.2009, 05:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 8.7.2005
Где: Москва, Россия

Репутация: нет
Всего: 11



Цитата(popovda @  1.4.2009,  22:00 Найти цитируемый пост)
Что до интерфейса - пользователь передаёт в C-функцию указатель type(C_PTR), и это всего лишь указатель, целое число. А целое - оно всегда целое. 

С x86 понятно - здесь указатели на все типы совпадают (даже если вспомнить про сегменты, которые несколько нарушают идею, что указатель = целое число). Меня интересовали другие архитектуры. В стандарте C явно оговаривается, что, например, (void*) и (double*) могут иметь разный размер и разное внутреннее представление. Отсюда и вопрос - как Фортрану указать вид указателя, принимаемого программой на C?
PM MAIL   Вверх
popovda
Дата 13.4.2009, 22:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 290
Регистрация: 9.6.2006
Где: Москва

Репутация: нет
Всего: 6



Кстати, на форуме Intel мне указали на ещё одну проблему - если, например, в структуре указать атрибут sequence, то некоторые данные C не правильно будет интерпретировать, например, у меня так было с символами. Дутчик категорически не рекомендовал использовать его при межъязыковом программировании. Если не изменяет память, Бартеньев, как раз наоборот, - рекомендовал.


--------------------
С уважением, Попов Д.А.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Fortran | Следующая тема »


 




[ Время генерации скрипта: 0.0684 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.