2012-02-24 2 views
0

Добрый день. Извините, возможно, не очень понятное определение моей проблемы и, возможно, некоторые неточности - я только начинаю попробовать себя в программировании. Тем не менее, я постараюсь изо всех сил объяснить все просто.Совместимость символов символов C-Fortran

У меня есть математическая библиотека, написанная на Фортране.

Например, есть функция. Эта функция используется для анализа имени файла журнала в dll для наблюдения за вычислениями.

integer function initLog(
*       int_parameter, 
*       char_parameter, 
*       char_parameter_length, 
*      ) 
*bind(C, name = "initLog"); 
    use, intrinsic :: ISO_C_BINDING; 
    !DEC$ATTRIBUTES DLLEXPORT::initLog 

    integer(C_INT),   value :: parameter; 
    character(C_CHAR), intent(in) :: char_parameter(char_parameter_length); 
    integer(C_INT),   value :: char_parameter_length; 

    ... 

    some_other_variable = char_parameter(1:1)(1:char_parameter_length); 

    end function; 

Обычно я использую MATLAB для работы с DLL и, таким образом, должны использовать .mex файлы называть свои функции непосредственно из MATLAB. Внутри файла .mex у меня есть код интерфейса, написанный на C, который обеспечивает интерфейс между MATLAB и dll. Например, интерфейс C для функции упомянутого является:

int doSmth(const int int_parameter, 
      const char* char_parameter, 
      const int char_parameter_length,); 

А потом я использую LoadLibrary и GetProcAddress, чтобы получить функцию. И это прекрасно работает.

Однако теперь мне нужно создать тестовый файл .exe в Fortran, который будет использовать мою dll. Итак, мне нужно связать свою dll с exe, связав ее с библиотекой import .lib. Другой вариант для этого исполняемого файла - взять имя файла журнала через командную строку в качестве параметра. Итак, сначала я пытался передать лог файл только из файла EXE, как это:

program test 
    use dll_name; 
    use ifport; 
    implicit none; 
    ... 
    integer :: log_init_status; 
    ... 
    log_init_status = init_log(2, 'logfile.log', len('logfile.log')); 
    ... 
end program 

Это отлично работает в версии, но возвращает «тяжелый (664): Вне диапазона: подстроки конечной позиции ' 11 'больше, чем ошибка длины строки' 1 '' в отладке. Но сначала я не нашел эту ошибку и продолжал писать код. Это то, что я получил в настоящее время:

program test 
    use dll_name; 
    use ifport; 
    use ISO_C_BINDING; 
    implicit none; 
    ... 
    character*255  :: log_flag_char; 
    integer(C_INT) :: log_flag; 
    character*255  :: filename; 
    character(C_CHAR) :: log_filename; 
    integer(C_INT) :: log_filename_length; 

    .... 

    call getarg(5, log_flag_char); 
    read(log_flag_char, *) log_flag; 

    call getarg(6, log_filename); 
    log_filename_length = len(log_filename); 

    log_init_status = analyticsLogInit(log_flag, log_filename, log_filename_length); 

    ... 

end program 

Это работало отлично, но взял только один первый символ log_filename («C: \ ABCD \ logfile.log» превращается в «C»). Если я изменю

знак (C_CHAR) :: log_filename;

к

символ (C_CHAR) :: log_filename (255);

, я получаю 2 проблемы: во-первых, у меня есть длина моего log_filename равный 255 (может быть исправлено аккуратным, хотя), а второй - и главное - я снова получить «тяжелый (664): Out диапазона: конечная позиция подстроки '255' больше длины строки '1' ".

Если изменить

log_init_status = analyticsLogInit (log_flag, log_filename, log_filename_length);

к

log_init_status = analyticsLogInit (log_flag, C_LOC (log_filename), log_filename_length);

, я получаю сообщение об ошибке типа фиктивного аргумента, отличного от фактического.

Я сам есть ощущение, что ошибка 664 показано происходит от этой линии в DLL:

some_other_variable = char_parameter (1: 1) (1: char_parameter_length);

. Я должен написать в своем exe что-то вроде

знак * 255 :: log_filename;

и не

символов :: log_filename (255);

Но как его разобрать с помощью (C_CHAR)?

Я понимаю, что все это довольно грязно, и все это происходит из-за утечки понимания, но это мой почти первый серьезный опыт в программировании.

ответ

2

Я только взглянул на ваш вопрос, но одна вещь, которую следует обратить внимание, это то, как объявляется переменная или названная константа character. Вы можете указать два типа параметров: длина и вид. Если вы не используете соответствующее ключевое слово в объявлении, первый параметр указывает длину, а второй (если присутствует) указывает вид.
Так что, если вы хотите объявить переменную символов длиной 255 и любезное C_CHAR, вы можете сделать это в любом из следующих способов:

character(len=255, kind=C_CHAR) :: log_filename 
character(255, kind=C_CHAR)  :: log_filename 
character(255, C_CHAR)   :: log_filename 
character(kind=C_CHAR, len=255) :: log_filename 
character(kind=C_CHAR)   :: log_filename*255 

следующий синтаксис с другой стороны (это тот, который вы использовали) объявляет переменную character длины C_CHAR, независимо от того, какое значение может быть.

character(C_CHAR) :: log_filename 

О, а следующий синтаксис объявляет массив из 255 элементов, причем каждый элемент переменной длины символа C_CHAR.

character(C_CHAR) :: log_filename(255) 

Поэтому вывод, что один должно занять некоторое время, чтобы изучить особенности декларирования символьных сущностей в Fortran.

+0

Благодарим за ответ. Конечно, я понимаю, что в Фортране для меня есть много дел.Тем не менее, я был уверен, что синтаксис character (C_CHAR) :: log_filename отлично работает, поскольку он работает с целыми числами и удваивает (и потому, что он был написан в прочитанной статье) – AntalOvc

+0

Увы, смена символа (C_CHAR) на «character (kind = C_CHAR)» ничего не давал. Кроме того, теперь я не понимаю, как «some_other_variable = char_parameter (1: 1) (1: char_parameter_length);» работает, если объявлен как «символ (C_CHAR), намерение (in) :: char_parameter (char_parameter_length)»; – AntalOvc

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