2010-05-23 35 views
30

Tôi đã đọc mục nhập của nó trong tài liệu tham khảo ngôn ngữ (của Intel), nhưng tôi không thể nắm bắt được những gì nó làm. Có thể ai đó trong thuật ngữ của giáo dân giải thích nó với tôi, nó có nghĩa là gì khi nó được bao gồm trong một mô-đun?fortran SAVE statement

+0

Cũng thấy http://stackoverflow.com/questions/2582409/are-local-variables-in-fortran-77-static-or-stack-dynamic/2583248 –

+7

Như một bổ sung cho các câu trả lời rất hay mà bạn có, đề nghị của tôi là: "không bao giờ sử dụng lưu". Đó là một công thức cho thảm họa và làm cho các chủ đề không thường xuyên an toàn và không phải là không quốc tịch. Có thể có lý do để sử dụng lưu, nhưng chúng rất, rất hiếm và bạn có thể làm tương tự bằng cách sử dụng một giải pháp hoặc kiểu lập trình khác. –

Trả lời

37

Trong trường hợp một mô-đun nằm ngoài phạm vi, các biến của mô-đun đó trở thành không xác định - trừ khi chúng được khai báo với thuộc tính SAVE hoặc câu lệnh SAVE được sử dụng. "Không xác định" có nghĩa là bạn không được phép dựa vào biến có giá trị trước đó nếu bạn lại sử dụng mô-đun - nó có thể có giá trị trước đó khi bạn truy cập lại mô-đun hoặc có thể không - không có bảo đảm . Nhưng nhiều trình biên dịch không làm điều này cho các biến số mô-đun - các biến có thể giữ lại giá trị của chúng - nó không đáng để nỗ lực tìm ra một mô-đun có nằm trong phạm vi hay không và có lẽ các biến mô-đun được xử lý dưới dạng biến toàn cầu - nhưng không dựa vào điều đó! Để an toàn, hãy sử dụng "lưu" hoặc "sử dụng" mô-đun từ chương trình chính để chương trình không bao giờ nằm ​​ngoài phạm vi.

"tiết kiệm" cũng rất quan trọng trong thủ tục, để lưu trữ "nhà nước" qua lời gọi của chương trình con hoặc chức năng (như được viết bởi @ire_and_curses) - "gọi đầu tiên" khởi tạo, quầy vv

subroutine my_sub (y) 

integer :: var 
integer, save :: counter = 0 
logical, save :: FirstCall = .TRUE. 

counter = counter + 1 

write (*, *) counter 

if (FirstCall) then 
    FirstCall = .FALSE. 
    .... 
end if 

var = .... 

vv

Trong đoạn mã này, "bộ đếm" sẽ báo cáo số lượng lời gọi của chương trình con x. Mặc dù thực sự ở Fortran> = 90 người ta có thể bỏ qua "lưu" vì việc khởi tạo trong khai báo ngụ ý "lưu".

Ngược lại với trường hợp mô-đun, với trình biên dịch hiện đại, không có thuộc tính lưu hoặc khởi tạo-trên-khai báo, nó là bình thường đối với các biến địa phương của thủ tục để mất giá trị của họ trên invocations. Vì vậy, nếu bạn cố gắng sử dụng "var" trên một cuộc gọi sau đó trước khi xác định lại nó trong cuộc gọi đó, giá trị là không xác định và có thể sẽ không phải là giá trị được tính trên lời gọi trước đó của quy trình.

Điều này khác với hành vi của nhiều trình biên dịch FORTRAN 77, một số trong đó giữ lại giá trị của tất cả các biến cục bộ, mặc dù điều này không được yêu cầu theo tiêu chuẩn ngôn ngữ. Một số chương trình cũ được viết dựa trên hành vi không chuẩn này - những chương trình này sẽ thất bại trên các trình biên dịch mới hơn. Nhiều trình biên dịch có một tùy chọn để sử dụng hành vi không chuẩn và "lưu" tất cả các biến cục bộ.

EDIT SAU: cập nhật với một mã ví dụ cho thấy sai sử dụng một biến địa phương mà nên có một pha cứu thuộc tính nhưng không:

module subs 

contains 

subroutine asub (i, control) 

    implicit none 

    integer, intent (in) :: i 
    logical, intent (in) :: control 

    integer, save :: j = 0 
    integer :: k 

    j = j + i 
    if (control) k = 0 
    k = k + i 

    write (*, *) 'i, j, k=', i, j, k 

end subroutine asub 

end module subs 

program test_saves 

    use subs 
    implicit none 

    call asub (3, .TRUE.) 
    call asub (4, .FALSE.) 

end program test_saves 

biến địa phương k của chương trình con là cố ý bị lạm dụng - trong chương trình này nó được khởi tạo trong cuộc gọi đầu tiên kể từ khi điều khiển là TRUE, nhưng trên cuộc gọi thứ hai, điều khiển là FALSE, vì vậy k không được xác định lại.Nhưng không có thuộc tính lưu k không được xác định, do đó việc sử dụng giá trị của thuộc tính là bất hợp pháp.

Biên soạn chương trình với gfortran, tôi thấy rằng k giữ lại giá trị của nó anyway:

i, j, k=   3   3   3 
i, j, k=   4   7   7 

Biên soạn chương trình với ifort và tối ưu hóa tích cực lựa chọn, k bị mất giá trị của nó:

i, j, k=   3   3   3 
i, j, k=   4   7   4 

Sử dụng ifort với các tùy chọn gỡ lỗi, các vấn đề đã được phát hiện trong thời gian chạy!

i, j, k=   3   3   3 
forrtl: severe (193): Run-Time Check Failure. The variable 'subs_mp_asub_$K' is being used without being defined 
+0

Có lẽ cũng đáng nói rằng nó giống như từ khóa "tĩnh" trong C. – MasterHD

+0

_ "sử dụng" mô-đun từ chương trình chính để nó không bao giờ ra khỏi phạm vi_, bây giờ tôi thấy rõ ràng tại sao tôi không gặp vấn đề gì ngay cả khi viết thậm chí không có một 'TIẾT KIỆM 'trong chương trình của tôi! Cảm ơn bạn! –

3

Thông thường, các biến cục bộ nằm ngoài phạm vi khi thực thi rời khỏi quy trình hiện tại và do đó không có 'bộ nhớ' giá trị của chúng trên các lời gọi trước đó. SAVE là một cách để xác định rằng một biến trong một thủ tục nên duy trì giá trị của nó từ một cuộc gọi đến tiếp theo. Nó hữu ích khi bạn muốn lưu trữ trạng thái trong một thủ tục, ví dụ để giữ một tổng số đang chạy hoặc duy trì cấu hình của một biến.

Có một good explanation here, với ví dụ.

+0

Uhmm, bạn có thể đưa ra một ví dụ về điều đó không? Nếu tôi hiểu chính xác, nếu tôi khai báo SAVE trong một mô-đun, các biến của nó không thể thay đổi giá trị trong các chương trình con? –

+0

@Friedrich Schwartz: Không hoàn toàn. Bạn vẫn có thể đặt giá trị mới, nhưng nếu bạn kiểm tra giá trị của biến trước khi đặt, bạn sẽ thấy giá trị cuối cùng bạn đã đặt biến. Không có 'SAVE', bạn sẽ thấy 'không xác định'. Làm việc thông qua một ví dụ đơn giản nên làm cho nó rõ ràng hơn. –

4

Đăng câu trả lời này cho M.S.B. vì thiếu định dạng trong các nhận xét có thể là làm cho bữa sáng của lợn trong toàn bộ điều:

Đầu tiên, cảm ơn bạn đã trả lời, cả hai. Tôi đánh giá cao nó.

Nếu tôi hiểu đúng;

subroutine save(j) 
    implicit none  

    integer :: i = 0, j 
    save i 

    i = i + j 
    write(*,*)i 

    end subroutine save 


    program test_save 
    implicit none 

    integer :: j 

    j = 1 

    call save(j) 
    call save(j) 

    end program test_save 

không phải cho tuyên bố SAVE trong ví dụ trên, biến i (giá trị của biến) sẽ bị "mất" sau lần gọi đầu tiên lưu chương trình con. Nhờ đó, nó giữ nguyên giá trị của nó - "1" trong trường hợp này, và vì nó, nó tăng lên "2" trong lần gọi thứ hai.

Tôi đã nhận đúng chưa? Gần có thể?

+4

Có, câu lệnh SAVE làm cho biến i giữ lại giá trị của nó. Một cách tinh tế là trong ví dụ này, trong Fortran 90, câu lệnh lưu là tùy chọn - "lưu" tự động áp dụng vì "i" được khởi tạo trong một khai báo. Câu lệnh lưu sẽ là bắt buộc trong FORTRAN 77. –

2

Một giải thích ngắn có thể là: thuộc tính save nói rằng giá trị của một biến phải được bảo toàn qua các cuộc gọi khác nhau đến cùng một chương trình con/chức năng. Nếu không bình thường khi bạn quay trở lại từ một chương trình con/hàm, các biến "cục bộ" sẽ mất các giá trị của chúng kể từ khi bộ nhớ chứa các vars được lưu trữ. Nó giống như static trong C, nếu bạn biết ngôn ngữ này.