Я хотел бы связать программу Fortran с произвольным двоичным файлом. Я использую gfortran и нашел здесь ту же задачу легко выполнить с помощью gcc, используя objcopy от binutils .
Однако я не могу заставить его работать с gfortran.
Вот рабочий тривиальный пример с gcc
Во-первых, build.c
для создания файла данных, содержащего только двоичное представление числа pi=3,14...
#include <math.h>
#include <stdio.h>
int main() {
FILE *f;
double x = M_PI;
f = fopen("data.bin", "wb");
fwrite(&x, sizeof x, 1, f);
fclose(f);
return 0;
}
Затем cbin.c
, чтобы напечатать число.
# include <stdio.h>
extern double val;
int main() {
printf("%lf\n", val);
return 0;
}
Затем, чтобы создать исполняемый файл, я делаю это
objcopy -I binary -O elf32-i386 -B i386 --redefine-sym _binary_data_bin_start=_val data.bin data.o
objdump -t data.o
gcc cbin.c data.o
Обратите внимание, что начало данных переименовано в _val
.
Я пробовал следующее с gfortran
program forbin
implicit none
double precision :: val
common val
print *, val
end program
затем
objcopy -I binary -O elf32-i386 -B i386 --redefine-sym _binary_data_bin_start=_val_ data.bin data.o
objdump -t data.o
gfortran forbin.f95 data.o
Теперь начало данных переименовано в _val_
, чтобы следовать соглашению об именах gfortran. Шаг компиляции работает, но при выполнении печатается число 0 вместо пи, значит что-то пошло не так. Я даже не уверен, что common
- это правильно, и мне интересно, может ли быть какая-то путаница между адресом и значением. Кроме того, меня бы интересовали данные массива, а не один скаляр (я могу сделать это и в C, используя указатель на val).
Любая идея о том, что я должен сделать, чтобы сделать эту работу?
Если это важно, я работаю с gcc 4.9.1 из здесь, в Windows 7, 32-разрядная версия. Изначально я делаю это для создания DLL для использования в Excel. Я мог бы сделать это на C, но я бы предпочел, если возможно, подход на чистом Fortran.
изменить
Следуя предложению High Performance Mark и этой страницы из Stack Overflow, вот решение для скалярных данных.
module binmod
use iso_c_binding, only: c_double
real(c_double), bind(c) :: val
end module
program forbin
use binmod
implicit none
print *, val
end program
И, конечно же, я использую имя C _val
вместо _val_
.
Однако, делая это с массивом, я все еще не понимаю, как использовать символы из data.o
для объявления массива в Фортране. Я мог бы написать размеры вручную, но это не кажется очень надежным (было бы легко забыть обновить код Fortran, если бы я обновил данные).
Вот вывод из objdump -t data.o
00000000 l d .data 00000000 .data
00000000 g .data 00000000 _val
00000008 g .data 00000000 _binary_data_bin_end
00000008 g *ABS* 00000000 _binary_data_bin_size
Глобальный _binary_data_bin_end
— это маркер конца данных, аналогичный _binary_data_bin_start
, который я переименовал в _val
, а _binary_data_bin_size
— это «абсолютное» значение. В C это последнее значение можно было бы напечатать с помощью
extern char binary_data_bin_size;
...
printf("%d\n", &binary_data_bin_size);
Однако я даже не понимаю, как здесь может работать указатель, даже если не учитывать предупреждение от компилятора. Это работает, но я не знаю, как и как адаптировать его к gfortran.