ผ่านอาร์เรย์ที่จัดสรรจากรูทีนย่อยไปยังโปรแกรมหลักใน Fortran ใช้หรือโมดูล? อินเตอร์เฟซ?

Aug 16 2020

ฉันต้องการจัดสรรอาร์เรย์ในรูทีนย่อยจากนั้นใช้อาร์เรย์นี้ในโปรแกรมหลักและส่งต่อไปยังรูทีนย่อยอื่น ๆ ในอดีต (F77?) การส่งผ่านสามารถทำได้ในบล็อกทั่วไป แต่ในปัจจุบันขั้นตอนที่ได้รับความนิยมดูเหมือนจะใช้โมดูล เมื่อฉันลองสิ่งนี้ดังตัวอย่างโค้ดคอมไพเลอร์บอกฉัน

Rank mismatch in argument ‘f’ at (1) (scalar and rank-1)

เห็นได้ชัดว่าโปรแกรมหลักคิดว่า 'f' เป็นสเกลาร์: แต่ฉันอ่านรหัสนี้หมายความว่าฉันได้ประกาศว่าเป็นอาร์เรย์หนึ่งมิติทั้งในรูทีนย่อยและในโปรแกรมหลัก ฉันขาดอะไรไป?

ฉันได้ลองใช้รูปแบบต่างๆเช่นการประกาศตัวแปรเป็นส่วนหนึ่งของโมดูล แต่ไม่มีสิ่งใดที่ฉันคิดได้ว่าการคอมไพล์นั้นปราศจากข้อผิดพลาด (และบางอันก็ทำให้เกิดข้อผิดพลาดอีกมากมาย ;-() ขอขอบคุณข้อมูลเชิงลึกใด ๆ

          module subs
        contains
        subroutine makef(f)
        end subroutine makef
      end module subs
c-----------------------------------------------------------------------
      program work

      use subs
      implicit none
        real, allocatable :: f(:)

      call makef(f)

      write (*,*) f
      stop
      end
c---------------------------------------------------------------------
      subroutine makef(f)
      implicit none

      real, allocatable, intent(out) :: f(:)
      integer :: i
      integer :: is

      is=10
      allocate(f(-is:is))

      do i=-is,is
        f(i)=i
      end do
      return
      end subroutine makef

คำตอบ

2 francescalus Aug 16 2020 at 17:19

โมดูลใน Fortran ไม่เหมือนกับไฟล์ส่วนหัวในภาษาอื่นซึ่งเป็นเพียงข้อมูลเกี่ยวกับสิ่งที่กำหนดไว้ที่อื่น มีแนวคิดของ "นิยามรอการตัดบัญชี" (โมดูลย่อย) แต่ในกรณีนี้โมดูลควรพูดทุกอย่างเกี่ยวกับรูทีนย่อยไม่ใช่เพียงแค่พยายามชี้ไปที่การมีอยู่ของมัน

ในตัวอย่างของคำถามเรามี: โปรแกรมหลัก; โมดูลsubsกับขั้นตอนโมดูลmakef; makefย่อยภายนอก

โปรแกรมหลักที่ใช้โมดูลsubsและขั้นตอนของมันmakefดังนั้นการอ้างอิงในโปรแกรมหลักที่จะเป็นขั้นตอนโมดูลที่ไม่ย่อยภายนอกmakefmakef

รูทีนย่อยโมดูลmakefมีอาร์กิวเมนต์fที่ไม่มีคำสั่งการประกาศทำให้เป็นฟังก์ชันสเกลาร์ / ภายนอกที่ประกาศโดยปริยาย นี่คือข้อความของคอมไพเลอร์ ใช้implicit noneในโมดูลเช่นเดียวกับในโปรแกรมหลักและรูทีนย่อยภายนอกที่นี่

คำจำกัดความทั้งหมดของรูทีนย่อยควรอยู่ในโมดูล:

module subs
  implicit none
contains
  subroutine makef(f)
    real, allocatable, intent(out) :: f(:)
    integer :: i
    integer :: is

    is=10
    allocate(f(-is:is))

    do i=-is,is
      f(i)=i
    end do
  end subroutine makef
end module subs

หรือหากต้องการอ้างถึงการนำโพรซีเดอร์ภายนอกไปใช้ในภายหลังบล็อกอินเทอร์เฟซสามารถมีคุณลักษณะในโมดูลโดยไม่ต้องประกาศรูทีนย่อย ในกรณีนี้จำเป็นต้องระบุอินเทอร์เฟซที่สมบูรณ์:

module subs
  implicit none

! An interface block to give an explicit interface to the external subroutine makef
  interface
     subroutine makef(f)
       implicit none
       real, allocatable, intent(out) :: f(:)
     end subroutine makef
  end interface
end module subs

ในกรณีนี้ไม่ต้องการบล็อกอินเทอร์เฟซ

VladimirF Aug 16 2020 at 13:07

คุณวางสำเนาของบรรทัดแรกและบรรทัดสุดท้ายลงในโมดูลเท่านั้น ที่ไม่สามารถทำงานได้ คุณต้องย้ายรูทีนย่อยทั้งหมดลงในโมดูล