2017-02-03 6 views
0

Я изучаю основы Fortran. Я создал простую подпрограмму инициализации матрицы:Неверный результат при использовании глобальной переменной в Fortran

program test 
    integer, parameter :: n = 1024 
    real :: a(n, n) 
    call init(a) 
    write (*, *) a(1, 1) 
end program 

subroutine init(a) 
    real :: a(n, n) 
    a(:, :) = 3.0 
end subroutine 

Тогда выход является 0.0 вместо ожидаемого 3.0. Кроме того, valgrind говорит, что:

==7006== Conditional jump or move depends on uninitialised value(s) 
==7006== at 0x400754: init_ (in /home/marcin/proj/mimuw/fortran/test) 
==7006== by 0x4007A4: MAIN__ (in /home/marcin/proj/mimuw/fortran/test) 
==7006== by 0x40083B: main (in /home/marcin/proj/mimuw/fortran/test) 

Почему? Параметр n правильно распознается компилятором и должен быть глобальным.

Я составил программу с gfortran 6.3.1

+0

Возможно, вы думаете о внутренней процедуре. – tim18

+2

'n' не является глобальным объектом. Если вы добавите 'implicit none' в подпрограмму, вы увидите ошибку. – francescalus

+0

О, так что мне тоже нужно 'implicit none' в подпрограммах! Не знал об этом. При тестировании я пытался использовать это в 'program', но не в' подпрограмме'. Можно ли использовать 'implicit none' глобально? – marmistrz

ответ

5

n не является глобальной переменной, это локальная переменная основной программы.

Подпрограмма - это полностью независимая единица компиляции из основной программы, и они не разделяют никакой информации.

Подпрограмма может «видеть» другие переменные родительского модуля, если это модульная процедура или переменные родительской (хост) процедуры или программы, если это внутренняя процедура.

Обязательно прочтите информацию о структуре программ Fortran и используйте модули как можно больше. Предпочитайте модули над внутренними процедурами. Вы увидите, как включить подпрограмму в модуль или как сделать его внутренним по отношению к основной программе в ссылке.

Я не упомянул об общих блоках, просто не использую их, они устарели. И помните, чтобы использовать implicit none в каждом блоке компиляции.

+0

Так что 'n' было просто объявлено неявно, когда я использовал его в подпрограмме? – marmistrz

+1

@marmistrz yes, с неявным вводом всего, что начинается с i, n и некоторых других букв (даже не помню, какие) объявляются целыми числами. Как правило, вы не должны использовать неявное типирование, поскольку это иногда может привести к нежелательному поведению. Я могу предложить прочитать Modern Fortran, объясненный Майклом Меткалфом - это может помочь вам в процессе onboarding. – Chaosit

1

Предполагая, что вы хотите его повсюду, тогда вы используете COMMON-блок в эпоху f77 и теперь MODULE.

I CAPITALIZED большая часть изменений. И если нет ошибки, вы получите несколько способов рассмотреть понимание N в SUBROUTINE, и ЭЛЕМЕНТНАЯ ФУНКЦИЯ, вероятно, стоит попробовать здесь.

MODULE MyMODULE 
    integer, parameter :: n = 1024 
END MODULE MyMODULE 

!%%%%%%%%%% 
program test 
USE MyModule 
IMPLICIT NONE 
! done up in ˆmoduleˆ...! integer, parameter :: n = 1024 
REAL, DIMENSION(n,n) :: A 

CALL Alternative_Init(A, 3.3) 
WRITE (*,*) a(1, 1) 

CALL Alternative2_Init(A, n, 1.23) 
WRITE (*,*) a(1, 1) 

call init(a) 
write (*, *) a(1, 1) 
END PROGRAM TEST 

!%%%%%%%%%% 
subroutine init(a) 
USE MyModule 
IMPLICIT NONE 

real :: a(n, n) 
a(:, :) = 3.0 

RETURN 
END SUBROUTINE init 


!%%%%%%%%%% 
SUBROUTINE Alternative_Init(a, Val4A) 
USE MyModule 
IMPLICIT NONE 

REAL, DIMENSION(:,:) , INTENT(INOUT) :: a 
REAL     , INTENT(IN ) :: Val4A 

a(:, :) = Val4A 
! or just... A = Val4A ! which does them all too. 

RETURN 
END SUBROUTINE Alternative_Init 

!%%%%%%%%%% 
SUBROUTINE Alternative2_Init(a, n, Val4A) 
!!!! USE MyModule 
IMPLICIT NONE 

INTEGER    , INTENT(IN ) :: n 
REAL, DIMENSION(n,n) , INTENT( OUT) :: a 
REAL     , INTENT(IN ) :: Val4A 

A = Val4A 

RETURN 
END SUBROUTINE Alternative2_Init