Может ли аргумент назначаемого намерения (inout) быть необязательным?

У меня проблема с попыткой определить подпрограмму, аргумент которой содержит назначаемую, необязательную переменную намерения (inout), показанную ниже. Код компилируется нормально, но при выполнении появляется ошибка «Ошибка сегментации - недопустимая ссылка на память».

Подпрограмма test_routine.f90

SUBROUTINE test_routine(A,B)

IMPLICIT NONE

    REAL,ALLOCATABLE,INTENT(IN)               :: A(:,:)
    REAL,ALLOCATABLE,OPTIONAL,INTENT(INOUT)   :: B(:,:)

    B = A
    B(:,:) = 1

END SUBROUTINE

Эта подпрограмма упакована в модуль и вызывается в Main.

Модуль test_module.f90

MODULE test_module

IMPLICIT NONE

    INTERFACE test_routine
        MODULE PROCEDURE test_routine
    END INTERFACE

END MODULE test_module

Основной test_main.f90

PROGRAM main

    USE test_module

IMPLICIT NONE

    REAL,ALLOCATABLE    :: A(:,:),B(:,:)

    ALLOCATE(A(6,6))
    ALLOCATE(B(6,6))
    A(:,:) = 0
    CALL test_routine(A,B)    ! WORKS FINE
    CALL test_routine(A)      ! DOESN'T WORK!

END PROGRAM main

Затем я попытался назначить другую переменную op_B, чтобы компенсировать B, которой на самом деле не существует, если основная процедура не передает ее. Однако следующий код по-прежнему не работает.

SUBROUTINE test_routine(A,B)

IMPLICIT NONE

    REAL,ALLOCATABLE,INTENT(IN)    :: A(:,:)
    REAL,ALLOCATABLE,OPTIONAL,INTENT(INOUT)   :: B(:,:)
    REAL,ALLOCATABLE               :: op_B(:,:)

    IF(.NOT. PRESENT(B)) THEN
        ALLOCATE(op_B(SIZE(A,1),SIZE(A,2)))
        B = op_B
    END IF
    B = A
    B(:,:) = 1

END SUBROUTINE

Кстати, я тоже пробовал использовать массив фиксированного размера, но все равно не помогает. Интересно, нельзя ли такое делать?


person Ruizhi    schedule 15.08.2017    source источник


Ответы (2)


Фиктивные аргументы могут быть необязательными, назначаемыми и намеренными (inout).

Но вам не разрешается определять или ссылаться на необязательный фиктивный аргумент, запрещать передачу его в PRESENT или связывать его с другим необязательным аргументом. Если «B» нет, вы не можете выполнить «B = A».

person IanH    schedule 15.08.2017

Основываясь на ответе @lanH, единственный способ, который я сейчас выяснил, - это дать псевдоним каждому необязательному фиктивному аргументу. Эта версия работает сейчас.

SUBROUTINE test_routine(A,B)

IMPLICIT NONE

    REAL,ALLOCATABLE,INTENT(IN)    :: A(:,:)
    REAL,ALLOCATABLE,OPTIONAL,INTENT(INOUT)   :: B(:,:)
    REAL,ALLOCATABLE               :: op_B(:,:)

    ALLOCATE(op_B(SIZE(A,1),SIZE(A,2)))
    op_B = A
    op_B(:,:) = 1

    IF(PRESENT(B)) THEN
        B = op_B
    END IF

    DEALLOCATE(op_B)

END SUBROUTINE
person Ruizhi    schedule 15.08.2017