반응형

     정보

    • 업무명     : 포트란을 활용한 인터페이스 : 개요, 외부 프로시저, 내부 프로시저, INTENT, 모듈

    • 작성자     : 이상호

    • 작성일     : 2020-12-03

    • 설   명      :

    • 수정이력 :

     

     내용

    [개요]

    • 안녕하세요? 웹 개발 및 연구 개발을 담당하고 있는 해솔입니다.

    • Fortran (포트란)은 수식 (Formular) 변환기 (Translator)의 약자로 과학 계산용으로 주고 사용되는 언어입니다.

    • 복잡한 계산 수행 성능이 뛰어나 공학과 자연과학 등 특정분야에 주로 사용되며 기상 데이터 처리를 위해 널리 사용되고 있습니다.

    • 오늘 포스팅은 포트란을 활용한 인터페이스를 소개합니다.

     

     

    [특징]

    • 기상 데이터 처리를 위해서 포트란 (Fortran)기술이 요구되며 이 프로그램은 이러한 목적을 달성하기 위한 기술서

     

    [기능]

    • 개 요

    • 외부 프로시저

    • 내부 프로시저

    • INTENT

    • 모듈

     

    [활용 자료]

    • 없음

     

    [자료 처리 방안 및 활용 분석 기법]

    • 없음

     

    [사용법]

    • 없음

     

    [사용 OS]

    • Linux (CentOS v7.8)

     

    [사용 언어]

    • gfortran v4.8.5

     

     세부 내용

    개요
    • 서브루틴과 함수를 말하는 프로시저는 메인 프로그램에 포함돼 있는 내부 프로시저와 메인 프로그램이나 모듈에 포함되지 않고 독립적으로 존재하는 외부프로시저 그리고 모듈 프로시저가 있습니다.

    • 메인 프로그램과 외부 프로시저는 서로 분리된 독립적인 프로그램 단위입니다. 

    • 메인 프로그램과 프로시저는 다른 프로시저에서 지역적으로 선언된 변수들에 접근 할 수 없으며 마찬가지로 외부 프로시저는 메인 프로그램에 선언된 변수에 접근 할 수 없습니다. 

    • 한 프로그램 단위에서 다른 단위로 정보를 전하기 위해서 함수에 인수를 전달하여야만 가능합니다.

    • 내부 프로시저는 하나의 프로그램 단위에 포함돼 있으므로 프로시저에 대한 참조에 대해서 인수의 개수와 타입 등의 속성들과 함수의 리턴 값 등이 바르게 사용 되었는지를 컴파일러가 점검할 수 있습니다. 

    • 비슷하게 모듈에 포함되는 모듈 프로시저 역시 모듈내의 문장으로 참조되거나 모듈에 대한 USE문을 사용함으로써 컴파일러가 인수와 결과 등이 올바른지 점검할 수 있도록 할 수 있습니다. 

    • 이와 같이 모듈 또는 내부 프로시저는 기본적으로 명시적 인터페이스 (explicit interface)를 가져 인수의 사용과 리턴 값 등에 대해 컴파일러가 오류를 점검할 수 있습니다. 

    • 반면 외부 프로시저는 메인 프로그램이나 다른 프로그램 단위와 분리되어 독립적으로 존재하므로 컴파일러가 프로시저에 대한 참조의 오류 여부를 점검할 수 없습니다. 

    • 외부 프로시저는 기본적으로 암시적 인터페이스 (implicit interface)를 가집니다.

     

    외부 프로시저
    • 포트란에서는 인터페이스 블록(interface block)을 이용하여 외부 프로시저에 대해 명시적 인터페이스를 제공합니다.

    • 인터페이스 블록은 컴파일러에게 프로시저 인수의 모양, 형태 등의 속성을 알려 주어 프로시저에 대한 참조의 오류 여부를 점검할 수 있도록 해줍니다.

    • 인터페이스 블록의 일반적인 형태는 다음과 같습니다.

    PROGRAM exercise
    
      INTERFACE 
        SUBROUTINE squrt(a,n)
          REAL :: a(n) 
        END SUBROUTINE 
      END INTERFACE 
      
      INTEGER, PARAMETER :: m = 100 
      REAL :: q(m) q=71
      
      CALL squrt(q,m) 
    END PROGRAM exercise

     

    • 이렇게 인터페이스 블록을 사용하여 외부프로시저에 대한 명시적 인터페이스를 정의해주면 다음과 같은 예제처럼 컴파일 단계에서 에러가 발생해 의도치 않은 코딩 실수를 줄일 수 있습니다.

    PROGRAM inter
      INTERFACE 
        REAL FUNCTION ratio(x, y) 
          REAL::x, y 
        END FUNCTION ratio 
      END INTERFACE 
      
      INTEGER :: i=3, j=25
      
      PRINT *,'The ratio is ',ratio(i,j) 
    END PROGRAM inter 
    
    REAL FUNCTION ratio(x, y) 
      REAL:: x, y 
      ratio=x/y 
    END FUNCTION ratio

     

    • 위 예제는 메인프로그램과 외부 프로시저의 인수타입이 일치 하지 않아 컴파일 단계에서 다음과 같은 에러가 발생합니다.

    "test.f", line 9.34: 1513-061 (S) Actual argument attributes do not match those specified by 
    an accessible explicit interface. 
    ** inter === End of Compilation 1 === 
    ** ratio === End of Compilation 2 === 
    1501-511 Compilation failed for file test.f

     

    내부 프로시저
    • 프로그램 단위 내에 함수나 서브루틴 같은 프로시저가 올 수 있으며 이를 내부 프로시저라 합니다.

    • 모든 내부 프로시저는 그것을 포함하는 프로그램 단위의 맨 마지막 부분에서 CONTAINS문 다음에 위치해야 합니다.

    • 외부 프로시저와 그 형태는 동일하나 단지 END문 다음에 FUNCTION 또는 SUBROUTINE을 반드시 붙여 주어야 한다는 점이 다릅니다.

    • 내부 프로시저를 포함하는 프로그램 단위에서 선언된 변수는 내부 프로시저에서 접근할 수 있으며 내부 프로시저에서 다시 정의할 수도 있습니다.

    • 다음은 외부 프로시저에서 작성된 예제에서 인터페이스블록을 사용하지 않고 내부 프로시저를 이용하도록 수정 한 것입니다.

    PROGRAM explicit 
    
      INTEGER :: i=3, j=25 
      PRINT *,'The ratio is ',ratio(i,j) 
      
    CONTAINS 
      REAL FUNCTION ratio(x, y) 
        REAL:: x, y 
        ratio=x/y 
      END FUNCTION ratio 
    END PROGRAM explicit

     

    • 내부 프로시저는 명시적 인터페이스가 기본이므로 위 예제는 다음과 같이 컴파일러에 의해 오류가 발견됩니다.

    "inter.f", line 3.31: 1513-061 (S) Actual argument attributes do not match those specified by 
    an accessible explicit interface. 
    ** inter === End of Compilation 1 === 
    1501-511 Compilation failed for file inter.f.

     

    INTENT
    • 포트란에서는 보다 효율적인 컴파일 성능향상을 위해 INTENT 속성(attribute)을 이용해 프로시저내의 더미 인수들에 대한 계획된 이용(in, out, 또는 inout)을 컴파일러에게 알려 줄 수 있습니다.

      • INTENT(in) : 프로시저에 들어와서 나갈 때까지 값이 변함없는 인수

      • INTENT(out) : 프로시저 내에서 값을 할당 받을 때까지 사용되지 않는 인수

      • INTENT(inout) : 프로시저에 들어와 사용되고 값을 새로이 할당 받아 그 결과를 호출한 프로그램에되돌려 주는 인수

    SUBROUTINE meron(a, b, c, m, n) 
      REAL, DIMENSION(n, n), INTENT(IN) :: a 
      REAL, DIMENSION(m, m) :: b, c 
      INTENT(out) :: b 
      INTENT(inout) :: c 
      
      c = SQRT(c) 
      b = c + SUM(a) 
    END
    ! 인수 a는 프로시저 내에서 값이 변하지 않는다.
    ! 인수 b의 값은 프로시저 내에서 값을 할당 받을 때까지 사용되지 않는다.
    ! 인수 c는 프로시저 내에서 사용되고 값이 새로 할당된다. 

     

    • 포트란 프로그램에서 INTENT 속성을 반드시 사용해야 하는 것은 아닙니다.

    • 그러나 INTENT 속성을 사용함으로써 컴파일러는 코딩 오류 점검이 빨라지고 프로그램의 안정성을 높일 수 있습니다.

    • 만약 INTENT(in) 속성의 인수가 값을 할당 받거나 INTENT(out) 속성의 인수가 새로운 값을 할당 받지 않는다면 컴파일 단계에서 에러가 발생하게 될 것입니다.

    • 다음 예제처럼 INTENT 속성을 잘못 지정해 준 경우 컴파일 단계에서 에러가 발생 할 것 입니다.

    PROGRAM intent_err
    REAL :: x, y 
      y = 5. 
      CALL mistaken(x, y) 
      PRINT *, x 
    
    CONTAINS 
      SUBROUTINE miserr(a, b) 
        IMPLICIT NONE 
        REAL, INTENT(in) :: a
        REAL, INTENT(out) :: b 
        
        a = 2*b 
      END SUBROUTINE miserr
    END PROGRAM intent_err

     

    모듈
    • 모듈은 타입선언, 서브프로그램, 새로운 데이터 타입선언 등을 하나로 묶어 정의 할 수 있는 프로그램 단위로서 Fortran90에 새롭게 추가된 기능입니다.

    • 사용자는 모듈을 사용해서 보다 신뢰성 있고, 재사용이 쉬우며 작성하기도 쉬운 객체 기반의 코드를 작성할 수 있습니다.

    • 모든 프로그램 단위는 USE문을 이용해 모듈을 첨부할 수 있고 그렇게 해서 그 모듈이 제공하는 기능을이용할 수 있습니다.

    • Global Object Declaration

      • 모듈은 Fortran77의 COMMON과 INCLUDE문을 대신해 사용됩니다. 글로벌 데이터 설정이 필요한 경우 하나의 모듈에 그 데이터를 정의해 둡니다.

      • 이렇게 모듈에 정의된 데이터는 그 모듈을 첨부하는 어떤 프로그램 단위에서도 사용될 수 있으며 그 값은 각각의 모듈 첨부에 대해 일정하게 유지됩니다.

    • Interface Declaration

      • 인터페이스에 대한 정의도 모듈에 해두고 명시적 인터페이스가 필요할 때마다 모듈을 첨부해 사용할 수 있습니다.

    • Procedure Declaration

      • 프로시저를 모듈에 정의해서 그 모듈을 첨부한 어떤 프로그램 단위에서도 사용할 수 있도록 합니다.

    • Controlled Object Declaration

      • 접근 구문을 이용해 모듈에서 선언된 변수, 프로시저, 연산자 등의 노출 정도 (visibility)를 제어할 수 있습니다.

    • Packaged of Whole Sets of Facilities

      • 사용자 정의 타입, 프로시저, 연산자, generic 인터페이스 등을 정의하고 하나로 묶을 수 있어 간단한 객체 지향성을 제공합니다.

    • 모듈 프로그램 단위의 기본 모양은 다음과 같습니다.

    MODULE <module name>
      <declarations and specifications statements>
        [CONTAINS
      <definitions of module procedures>]
    END [MODULE [<module name>]]
    <module name>은 USE문에 사용되는 이름이고 파일명과 같을 필요는 없습니다.

     

    • Global data

      • 글로벌 변수를 모듈에 정의해 두면 이를 필요로 하는 프로그램은 USE문을 이용해 모듈을 첨부하여 글로벌 변수에 접근할 수 있습니다.

    MODULE global 
      REAL :: a, b, c 
      INTEGER :: i, j, k 
    END MODULE global

     

    • 위와 같이 정의된 모듈 globals를 첨부시키기 위해 프로그램 단위는 다음과 같이 USE문을 사용할 수 있다. 

    • 단, USE문은 프로그램 단위에서 제일 위에 위치해야 합니다.

    USE globals ! 모든 변수 접근 가능
    USE globals, ONLY: a, c ! a,c 특정 변수만 사용 가능
    USE globals, r => a, s => b ! 지역변수 r,s를 이용하여 a,b 변수 접근 가능

     

    • Procedure

      • 모듈은 다른 프로그램 단위가 접근할 수 있는 프로시저를 포함할 수 있습니다. 

      • 모듈 내에 위치하는 모듈 프로시저도 내부 프로시저와 같이 다음과 같은 점을 제외하고는 외부 프로시저와 동일한 모양을 가집니다.

        • CONTAINS 문 다음에 위치 해야 합니다.

        • END 문 다음에 FUNCTION 또는 SUBROUTINE이 있어야 합니다.

    MODULE module_pro
      TYPE point 
        REAL :: x, y 
      END TYPE point 
      
    CONTAINS 
      FUNCTION addpoints (p, q) 
        TYPE (point), INTENT(IN) :: p, q 
        TYPE (point) :: addpoints
        addpoints%x = p%x + q%x
        addpoints%y = p%y + q%y
      END FUNCTION addpoints
    END MODULE module_pro
    
    PROGRAM sum_p
      USE module_pro
      TYPE (point) :: px, py, pz
      
      px = point(1., 2.) 
      py = point(2., 5.) 
      pz = addpoints(px, py) 
      
      PRINT*, ' pz =', pz
    END

     

     참고 문헌

     문의사항

    [기상학/프로그래밍 언어]

    • sangho.lee.1990@gmail.com

    [해양학/천문학/빅데이터]

    • saimang0804@gmail.com
    반응형
    • 네이버 블러그 공유하기
    • 네이버 밴드에 공유하기
    • 페이스북 공유하기
    • 카카오스토리 공유하기