Совместимость строк символов C-Fortran

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

У меня есть математическая 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. Другой вариант для этого исполняемого файла — взять имя файла журнала через командную строку в качестве параметра. Итак, сначала я попытался передать имя файла журнала только из исполняемого файла, например:

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;

to

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

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

Если я изменюсь

log_init_status = analyticsLogInit(log_flag, log_filename, log_filename_length);

to

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

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

У меня самого такое ощущение, что показанная ошибка 664 исходит из этой строки в dll:

некоторая_другая_переменная = параметр_символа (1:1) (1:длина_параметра_символа);

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

символ*255 :: имя_файла_журнала;

и не

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

Но как я могу разобрать его с использованием (C_CHAR)?

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


person AntalOvc    schedule 24.02.2012    source источник


Ответы (1)


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

Таким образом, вывод таков, что следует потратить некоторое время на изучение особенностей объявления символьных сущностей в фортране.

person eriktous    schedule 24.02.2012
comment
Спасибо за ваш ответ. Конечно, я понимаю, что в Фортране мне нужно многому научиться. Тем не менее, я был уверен, что синтаксис character(C_CHAR) :: log_filename работает нормально, поскольку он работает с целыми числами и удвоениями (и потому, что это было написано в статье, которую я читал) - person AntalOvc; 27.02.2012
comment
Увы, смена символа(C_CHAR) на символ(kind=C_CHAR) ничего не дала. Кроме того, теперь я не понимаю, как some_other_variable = char_parameter(1:1)(1:char_parameter_length); работает, если он объявлен как символ (C_CHAR), намерение (в) :: char_parameter (char_parameter_length); - person AntalOvc; 27.02.2012