Совместимость символьной строки C-Fortran - PullRequest
0 голосов
/ 24 февраля 2012

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

У меня есть математическая DLL, написанная на фортране.

Например, есть функция. Эта функция используется для анализа имени файла журнала в 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 в Фортране, который бы использовал мою DLL. Итак, я должен связать мою DLL с exe, связав его с библиотекой импорта .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

Это работало нормально, но занимало только 1 первый символ имени файла_файла ("C: \ abcd \ logfile.log" преобразуется в "C"). Если я изменю

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

до

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

, я получаю 2 проблемы: во-первых, у меня длина имени log_file равняется 255 (хотя может быть исправлено с помощью обрезки), а во-вторых - и главное - я снова получаю "серьезно (664): вне диапазона: Конечная позиция подстроки '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)?

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

1 Ответ

2 голосов
/ 25 февраля 2012

Я только просмотрел ваш вопрос, но стоит обратить внимание на способ объявления переменной 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

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

character(C_CHAR) :: log_filename(255)

вывод заключается в том, что нужно изучить некоторое время, чтобы изучить особенности объявления сущностей в Фортране.

...