Я бы хотел превратить унаследованный код на Fortran в современный код, совместимый с Fortran, чтобы я мог включить предупреждения компилятора, проверку интерфейса и т. Д. На этом этапе я не хочу изменять функциональность, просто заставлю его работать как как можно ближе к тому, что было, и все равно оставляйте компиляторы счастливыми.
Моя текущая проблема заключается в том, что код во многих местах передает массивы неправильных типов, например реальный массив для подпрограммы, имеющий целочисленный фиктивный аргумент. Это не ошибка как таковая в коде, поскольку она является преднамеренной и работает как задумано (по крайней мере, в обычных конфигурациях). Теперь, как я могу сделать то же самое и при этом поддерживать код в соответствии? Рассмотрим следующий пример:
program cast
implicit none
double precision :: a(10)
call fill_dble(a,10)
call print_dble(a,10)
call fill_int(a,10)
!call fill_int(cast_to_int(a),10)
call print_dble(a,10)
call print_int(a(1),10)
!call print_int(cast_to_int(a),10)
call print_dble(a(6),5)
contains
function cast_to_int(a) result(b)
use iso_c_binding
implicit none
double precision, target :: a(*)
integer, pointer :: b(:)
call c_f_pointer(c_loc(a(1)), b, [1])
end function
end program
subroutine fill_dble(b,n)
implicit none
integer :: n, i
double precision :: b(n)
do i = 1, n
b(i) = i
end do
end subroutine
subroutine print_dble(b,n)
implicit none
integer :: n
double precision :: b(n)
write(6,'(10es12.4)') b
end subroutine
subroutine fill_int(b,n)
implicit none
integer :: n, b(n), i
do i = 1, n
b(i) = i
end do
end subroutine
subroutine print_int(b,n)
implicit none
integer :: n, b(n)
write(6,'(10i4)') b
end subroutine
Когда я компилирую и запускаю его (gfortran 4.8 или ifort 18), я получаю, как и ожидалось:
1.0000E+00 2.0000E+00 3.0000E+00 4.0000E+00 5.0000E+00 6.0000E+00 7.0000E+00 8.0000E+00 9.0000E+00 1.0000E+01
4.2440-314 8.4880-314 1.2732-313 1.6976-313 2.1220-313 6.0000E+00 7.0000E+00 8.0000E+00 9.0000E+00 1.0000E+01
1 2 3 4 5 6 7 8 9 10
6.0000E+00 7.0000E+00 8.0000E+00 9.0000E+00 1.0000E+01
Первая половина реального массива искажается целыми числами (поскольку целые числа составляют половину размера), но при печати в виде целых чисел "правильные" значения присутствуют. Но это несовместимый код. Когда я пытаюсь это исправить, активировав функцию cast_to_int
(и отключив вызовы без нее), я действительно получаю что-то, что компилируется без предупреждения, и с gfortran я получаю тот же результат. Однако с помощью ifort я получаю:
1.0000E+00 2.0000E+00 3.0000E+00 4.0000E+00 5.0000E+00 6.0000E+00 7.0000E+00 8.0000E+00 9.0000E+00 1.0000E+01
1.0000E+00 2.0000E+00 3.0000E+00 4.0000E+00 5.0000E+00 6.0000E+00 7.0000E+00 8.0000E+00 9.0000E+00 1.0000E+01
0******** 0 5 6 7 8 9 10
6.0000E+00 7.0000E+00 8.0000E+00 9.0000E+00 1.0000E+01
что я не могу понять. Более того, ifort с -O0
вылетает (а с другой версией этого не происходит).
Я знаю, что код все еще не совсем корректен, потому что указатель, возвращаемый cast_to_int
, все еще имеет размер 1, но я считаю, что это должно быть другой проблемой.
Что я делаю не так или как я могу заставить ifort делать то, что я хочу?
РЕДАКТИРОВАТЬ: После ответа @ VladimirF, я добавляю, после implicit none
:
subroutine fill_int(b,n)
!dec$ attributes no_arg_check :: b
integer :: n, b(n)
end subroutine
subroutine print_int(b,n)
!dec$ attributes no_arg_check :: b
integer :: n, b(n)
end subroutine
end interface
, но компиляция с предупреждениями по-прежнему выдает ошибку:
$ ifort cast2.f90 -warn all
cast2.f90(17): error #6633: The type of the actual argument differs from the type of the dummy argument. [A]
call fill_int(a,10)
--------------^
cast2.f90(20): error #6633: The type of the actual argument differs from the type of the dummy argument. [A]
call print_int(a(1),10)
---------------^
compilation aborted for cast2.f90 (code 1)