Добрый день. Извините за, возможно, не очень понятное определение моей проблемы и, возможно, за некоторые неточности - я только начинаю пробовать себя в программировании. Тем не менее, я постараюсь объяснить все ясно.
У меня есть математическая 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)?
Я понимаю, что все это довольно грязно и что все это происходит из-за утечки понимания, но это мой почти первый серьезный опыт программирования.