2016-01-16 2 views
3

Чтобы передать строку Fortran в C, скрытый параметр также передается с размером переменной. Вот рабочий Фортран определение и метод C (на самом деле C++/CLI):Как передать несколько строк Fortran на C?

interface 
    subroutine AppendExtension(
+  Filename) 
+  bind(C, name="AppendExtension") 
    character *1, intent(inout):: Filename 
    end subroutine AppendExtension 
    end interface 

и вот на C++/CLI, который вызывается:

extern "C" { 
    void __declspec(dllexport) __cdecl AppendExtension(
             char * name, 
             int buffersize) 
{ 
    String^ clistr = gcnew String(name); 
    clistr = System::IO::Path::ChangeExtension(clistr->Trim(), gcnew String("OUT")); 
    IntPtr p = Marshal::StringToHGlobalAnsi(clistr); 
    char *pNewCharStr = static_cast<char*>(p.ToPointer()); 
    int cstrlen = strlen(pNewCharStr); 
    memcpy_s(name, buffersize, pNewCharStr, cstrlen); 
    if (cstrlen < buffersize) 
    { 
    // backfill with spaces, since a Fortran string is spaces on the right. 
    memset(&name[cstrlen], ' ', buffersize-cstrlen); 
    } 
    Marshal::FreeHGlobal(p); 
} 

выше работает правильно (Intel Visual Fortran 2013 SP1).

Теперь я хочу передать две строки в функцию. Вот что я сделал:

interface 
    subroutine ParseSpec(
+  Filename, Corename) 
+  bind(C, name="ParseSpec") 
    character *1, intent(inout):: Filename 
    character *1, intent(inout):: Corename 
    end subroutine ParseSpec 
    end interface 

Вот вызов в действии:

 CHARACTER*80 FILE_SPEC 
     CHARACTER*200 CORE_NAME 
     CALL ParseSpec(FILE_SPEC, CORE_NAME) 

и вот на C++/CLI:

void __declspec(dllexport) __cdecl ParseSpec(char * name, char * corename, int namelen, int corelen) 
{ 
    // namelen and corelen both contain the length of "name". 
    ... 

Есть два скрытых переменных. Я думаю, что они должны быть для буферов для каждой из двух моих строк, для «Filename» и для «Corename». Но оба содержат буферный размер первого буфера, а именно 80.

Где я иду не так?

ответ

4

Вызывающее соглашение для процедур BIND (C) может сильно отличаться от соглашения о вызове по умолчанию, которое компилятор Fortran использует для вызовов Fortran для Fortran. Вы не должны полагаться на какие-либо скрытые аргументы длины CHARACTER (в общем случае вы также не должны ожидать, что скрытые аргументы имеют тип int). Я подозреваю, что вам просто повезло, учитывая то, что переменная Fortran CHARACTER выложена в памяти этим компилятором.

Компилятор не должен передавать длину для процедуры BIND (C), поскольку единственная длина переменной CHARACTER, совместимой с C, является одной. Однако, если фиктивный аргумент представляет собой массив (который вам нужен, если вы передаете строку, а не отдельный символ), SIZE этого массива может быть неотрицательным - правила ассоциации последовательности Fortran для KIND = C_CHAR символ означает, что вы можете связать скаляр с массивом.

All up - изменить объявление функции Fortran таким образом, чтобы символьные аргументы были массивами и добавляли аргументы, чтобы явно передавать длину этих массивов.

Использование свободного источника формы, и предполагая, что символ по умолчанию такой же, как C_CHAR вид:

interface 
    subroutine ParseSpec( & 
     Name, Name_len, & 
     Corename, Corename_len) & 
     bind(C, name="ParseSpec") 
    use, intrinsic :: iso_c_binding, only: c_int, c_char 
    integer(c_int), value :: Name_len 
    character(kind=c_char), intent(inout) :: Name(Name_len) 
    integer(c_int), value :: Corename_len 
    character(kind=c_char), intent(inout):: Corename(Corename_len) 
    end subroutine ParseSpec 
end interface 

USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT 
CHARACTER*80 FILE_SPEC 
CHARACTER*200 CORE_NAME 
CALL ParseSpec( & 
    FILE_SPEC, LEN(FILE_SPEC, KIND=C_INT), & 
    CORE_NAME, LEN(CORE_NAME, KIND=C_INT)) 
extern "C" void ParseSpec( 
    char* name, int name_len, 
    char* corename, int corelen); 
// Operations on name[0] to name[name_len-1] and 
// corename[0] through corename[core_len-1]... 

 Смежные вопросы

  • Нет связанных вопросов^_^