2011-07-07 12 views
11

Có cách nào để tạo các mảng có kích thước thay đổi trong Fortran trên ngăn xếp không? Phân bổ() không làm việc cho tôi, bởi vì nó đặt mảng trên heap. Điều này có thể dẫn đến sự cố song song (xem câu hỏi khác của tôi: OpenMP: poor performance of heap arrays (stack arrays work fine)). Tất nhiên, một số bộ nhớ thông minh quản lý sẽ cung cấp cho một cách xung quanh vấn đề đó, nhưng quản lý bộ nhớ trong Fortran âm thanh ngớ ngẩn.Các mảng kích thước biến đổi ở Fortran mà không phân bổ()

Về cơ bản, tôi đang tìm một tương đương Fortran các nội dung sau trong C:

scanf("%d", N); 
int myarray[N]; 

Để tái lặp: Tôi không muốn

Integer, PARAMETER :: N=100 
Integer, Dimension(N) :: myarray 

vì đây xác định kích cỡ mảng lúc biên dịch thời gian. Tôi cũng không muốn

Integer, Dimension(:), Allocatable :: myarray 
read(*,*) N 
Allocate(myarray(1:N)) 

vì nó đặt mảng trên heap.

Giúp đánh giá rất nhiều. Tôi đã rất hài lòng với mảng Allocatable cho đến khi cuộc gặp gỡ gần đây của tôi với vấn đề trong câu hỏi được trích dẫn ở trên. Nếu có một câu trả lời tiêu cực cho câu hỏi này, tôi sẽ rất nhiều đánh giá cao một liên kết đến nguồn.

Chỉnh sửa: xem nhận xét về câu trả lời của M.S.B. Một cách thanh lịch để làm điều này chỉ trở thành có thể ở Fortran 2008, và nó được thực hiện trong một cấu trúc block.

Trả lời

11

Fortran có thể tự động tạo mảng chỉ với khai báo nhập vào chương trình con, miễn là kích thước được biết tại thời gian chạy ... không yêu cầu tham số được khai báo thuộc tính tham số, chúng có thể là đối số, ví dụ ,

subroutine MySub (N) 

integer, intent (in) :: N 
real, dimension (N) :: array 

hợp lệ. Vì vậy, tại sao không quyết định kích thước của bạn "N" trong chương trình chính, hoặc một số chương trình con, sau đó gọi một chương trình con khác để tiếp tục. Có khả năng với cách tiếp cận này mảng sẽ được trên ngăn xếp. Như @eriktous đã viết, tiêu chuẩn ngôn ngữ Fortran không xác định hành vi này. Một số trình biên dịch chuyển đổi các mảng cục bộ sang heap qua một kích thước nhất định. Một số trình biên dịch cung cấp các tùy chọn để kiểm soát hành vi này. Đặt các mảng lớn trên heap có thể sẽ bị ghi đè bằng đệ quy hoặc OpenMP.

Bạn cũng có thể chuyển một mảng có thể phân bổ dưới dạng đối số thực tế cho một chương trình con mà không có đối số giả của chương trình con được khai báo là có thể phân bổ. Điều này có thể không giúp bạn quan tâm vì mảng ban đầu vẫn có khả năng nằm trên vùng heap.

+1

Cảm ơn, M.S.B.! Nặng như nó được so sánh với 'int array [N]' của C, nó thực hiện thủ thuật. – drlemon

+0

Bạn có thể làm điều gì đó gần hơn với C, tức là một tuyên bố ở giữa mã, sử dụng cấu trúc khối của Fortran 2008. Xem, ví dụ, p. 12 của ftp://ftp.nag.co.uk/sc22wg5/N1701-N1750/N1729.pdf. Tôi không biết trình biên dịch nào hỗ trợ điều này, hoặc liệu họ có hỗ trợ nó với OpenMP hay không. –

+3

Tôi có cấu trúc này trong mã của tôi, tuy nhiên tôi nhận thấy rằng theo mặc định gfortran vẫn đặt các mảng trên heap, và bây giờ tôi có malloc ở giữa các vòng chặt chẽ của tôi. Có vẻ như tùy chọn "-fstack-array" là cần thiết. – DaveP

5

Tiêu chuẩn Fortran không có khái niệm về ngăn xếp và đống, do đó, điều này sẽ được triển khai (tức là trình biên dịch) phụ thuộc. Xem tài liệu cho ví dụ: gfortran, nó có một tùy chọn

 
-frecursive 
    Allow indirect recursion by forcing all local arrays to be allocated on the stack. 

Trình biên dịch khác có thể có các tùy chọn tương tự. Có lẽ điều này làm những gì bạn muốn.

+0

Cảm ơn, đó là một ý tưởng thú vị! Tuy nhiên, các mảng 'cục bộ', mà các mảng này được áp dụng, là các mảng được tạo ra trong các hàm, mà kích thước mảng được truyền như một đối số intent (in). Trong các thử nghiệm của tôi, -frecursive không ảnh hưởng đến kết quả của Allocate(), nhưng đã có ảnh hưởng đến cách giải quyết thú vị này: 'chương trình con doit (n); số nguyên, ý định (trong) :: n; số nguyên, kích thước (1: n) :: myarray; ! blah; endroutine ... đọc (*, *) n; gọi doit (n) ' Trong trường hợp này, myarray dường như có được trên stack có và không có -frecursive. Một chút sai lầm, nhưng không phải là lừa.Tôi đang sử dụng gcc 4.4.3 trên x86_64. – drlemon

+0

@drlemon: Đúng vậy, tôi sợ tùy chọn cụ thể này sẽ không chính xác làm những gì bạn cần. Gcc 4.4.3 là loại cũ, đặc biệt là từ quan điểm của Fortran; phát triển gfortran đã được (và vẫn còn) khá tích cực. Nếu có thể, bạn có thể thử nếu phiên bản mới hơn vẫn hiển thị cùng một vấn đề. Ngoài ra, nếu tôi là bạn, tôi sẽ đặt câu hỏi của bạn trên danh sách gửi thư gfortran. Vì điều này liên quan đến chi tiết cụ thể của việc triển khai, các nhà phát triển sẽ biết rõ nhất những gì có thể và những gì không. – eriktous