2014-06-06 3 views
0

이것은 특정 질문 일 수 있지만이 두 컴파일러 (Compaq Visual Fortran 최적화 컴파일러 버전 6.5 및 minGW)로 메모리를 처리하는 방법과 관련이 있다고 생각합니다. Fortran 90에서 포인터를 사용하여 모범 사례에 대한 아이디어를 얻으려고합니다. 다음은 "out of the box"에서 gfortran 컴파일러의 경고 중 하나 인 "POINTER 값이 지정된 함수가 할당의 RHS에 표시됩니다"와 다른 컴파일러의 경고가 없다는 것입니다.Fortran 90의 컴파일러 시각 포트란과 gfortran의 차이점

module vectorField_mod 
    implicit none 

    type vecField1D 
    private 
    real(8),dimension(:),pointer :: x 
    logical :: TFx = .false. 
    end type 

    contains 

    subroutine setX(this,x) 
    implicit none 
    type(vecField1D),intent(inout) :: this 
    real(8),dimension(:),target :: x 
    logical,save :: first_entry = .true. 
    if (first_entry) nullify(this%x); first_entry = .false. 
    if (associated(this%x)) deallocate(this%x) 
    allocate(this%x(size(x))) 
    this%x = x 
    this%TFx = .true. 
    end subroutine 

    function getX(this) result(res) 
    implicit none 
    real(8),dimension(:),pointer :: res 
    type(vecField1D),intent(in) :: this 
    logical,save :: first_entry = .true. 
    if (first_entry) nullify(res); first_entry = .false. 
    if (associated(res)) deallocate(res) 
    allocate(res(size(this%x))) 
    if (this%TFx) then 
     res = this%x 
    endif 
    end function 

    end module 

    program test 
    use vectorField_mod 
    implicit none 

    integer,parameter :: Nx = 15000 
    integer :: i 
    real(8),dimension(Nx) :: f 
    type(vecField1D) :: f1 

    do i=1,10**4 
    f = i 
    call setX(f1,f) 
    f = getX(f1) 
    call setX(f1,f) 
    if (mod(i,5000).eq.1) then 
     write(*,*) 'i = ',i,f(1) 
    endif 
    enddo 
    end program 

이 프로그램은 두 컴파일러에서 모두 실행됩니다. 그러나 루프를 10 ** 4에서 10 ** 5로 변경하면 gfortran에 심각한 메모리 문제가 발생합니다.

CTR-ALT-DLT를 사용하고 "성능"을 열면 gfortran에서 실행하면 실제 메모리가 빠르게 증가하고 compaq 컴파일러에서는 움직이지 않는 것처럼 보입니다. 내 컴퓨터가 충돌하기 전에 나는 보통 취소한다. 그래서 나는 그것이 최대에 이른 후에 행동에 대해 확신하지 못한다.

이것은 파생 데이터 유형에서 필요한 포인터를 사용하는 적절한 방법으로 보이지 않습니다. 그래서 내 질문은 : 안전하게 인터페이스 및 기능 같은 종류의 유지하면서 포인터를 사용할 수 있습니까?

p.s. 주 프로그램은 건설적인 것을하지 않는 것 같습니다.하지만 요점은 루프가 메모리에 의해 제한되어야한다고 생각하지 않고 실행 시간의 함수 여야한다는 것입니다.

도움을 주시면 대단히 감사하겠습니다.

답변

2

이 코드에는 언어상의 오해 때문에 발생하는 몇 가지 문제가 있습니다. 이러한 문제는 특정 컴파일러와 관련이 없습니다. 코드 자체가 손상되었습니다.

개념적으로

, 그주의 :

  • 하나 포트란 프로그램 당 절차에 저장된 변수의 하나의 인스턴스 만이 (90)는
  • 함수 결과를 나타내는 변수는 항상 정의되지 않은 때마다 시작합니다 함수가 호출됩니다.
  • 포인터 범위 내의 포인터가 포인터 결과가있는 함수의 결과를 가리 키도록하려면 포인터 할당을 사용해야합니다.
  • 포인터가 할당 된 경우 일치하는 할당 취소가 있어야합니다.

잠상 논리 에러가 발생하고있는 getXsetX 절차 저장된 first_entry 변수가 getX 절차의 setX 절차와 절차 인스턴스 특정 상태에서 특정 목적으로 융합 상태로되어있다. 그것이 - include 문이 경우 이후에 여러 개의 문을 가진주의 -

처음 setX 어느 특정 this 개체의 x 포인터 요소라고 인해 if 문에 무효가됩니다 (가난한 스타일의 문제도 거기에있다 조건부의 영향을받는 첫 번째 것만!). setX다른this으로 다시 호출되면 first_entry는 false로 설정되고 this 개체는 올바르게 설정되지 않습니다. 대신에 this%TFX을 테스트 할 것으로 생각됩니다.

마찬가지로 처음으로 getX은 정의되지 않은 함수 결과 변수 res이 무효화됩니다. 그러나 모든 후속 호출에서 함수 결과는 무효화되지 않습니다 (함수 결과는 함수가 실행될 때마다 정의되지 않은 상태로 시작됨). 그러면 연관된 테스트에서 잘못 사용되거나 deallocate 문에서 실수로 사용됩니다. (정의되지 않은 연관 상태가 분리 된 것과 같은 것이 아니라는 것을 나타내는) 정의되지 않은 연관 상태가있는 포인터에 대해 연관성을 갖는 (또는 해당 문제에 대해 할당을 해제하는) 것은 불법입니다.

getX은 포인터 결과 할당 된 포인터에 의해 생성됩니다. 이 포인터는 함수를 평가 한 결과 값에 액세스하는 데 "일반"할당이 사용되므로 손실됩니다. 이 포인터는 잃어 버리기 때문에 포인터 할당을 취소하기 위해 일치하는 deallocate 문을 사용할 수 없습니다. 따라서 프로그램에서 메모리가 누수됩니다. 거의 확실하게 일어나야하는 것은 주 프로그램 (이 경우 f이지만 get_x 함수의 값을 가져 오는 것이지만 여러 가지 경우에는 f이 사용되므로 f_ptr ...이라고 부름) 자체가 있어야한다는 것입니다. 포인터이며, 포인터이 지정되어야합니다 - f_ptr => getX(f1)입니다. 후속 setX 호출 및 쓰기 문에서 f_ptr의 값을 사용한 후에 명시 적으로 할당을 취소 할 수 있습니다.

포인터 할당을 의도했을 때 우발적으로 정상 할당을 사용할 수있는 가능성은 포인터 결과가있는 함수를 사용하는 것이 권장되지 않는 이유 중 하나입니다. 포인터를 반환해야하는 경우 서브 루틴을 사용하십시오.

Fortran 95는 해당 구성 요소의 기본 초기화를 NULL로 허용하여 포인터 구성 요소 관리를 단순화합니다. (여러분이 타입 정의에서 디폴트 초기화를 사용하고 있다는 것에 주목하라.)

Fortran 2003 (또는 Fortran 95 + 대부분의 유지 보수 된 컴파일러가 지원하는 언어 레벨 인 할당 가능한 TR) 포인터 함수를 사용하여 발생할 수있는 많은 잠재적 인 오류를 제거하는 할당 가능한 함수 결과를 도입합니다.

포트란 95 + 할당 가능한 TR 지원은 요즘 그 시점에 만들어진 언어 개선 및 수정 포트란 90 언어 수준을 제한 (당신이 모호한 플랫폼의 일종으로 작동하지 않는 경우가) 솔직히이되도록 유용 그래서 유비 쿼터스 어리석은.

+0

마지막 질문에서 대답을 수락하지 않아 죄송합니다. 매우 유사했습니다. 그리고 끈기있게 해주셔서 감사드립니다. 이 주석은 많은 의미가 있으며, 현재는 포인터를 반환하기 위해 서브 루틴을 사용하는 것에 전념 할 것이라고 생각합니다. 또한, 나는 그것이 내 상황에 도움이 될 것이라고 생각하지 않기 때문에 first_entry 저장된 변수를 제거 할 것이다. 나는 무효화하고 내가 작업하고있는 데이터 구조 때문에 상위 레벨에서 수행되어야한다고 생각한다. 다시 한 번 고맙습니다. @IanH – Charlie