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