2011-01-25 27 views
8

Tôi đang cố gắng tạo trình bao bọc Haskell cho thư viện C. Các cấu trúc cơ bản quá phức tạp để thể hiện như các kiểu tường minh, và tôi không thực sự sử dụng chúng ngoài việc chuyển giữa các hàm C, vì vậy tôi đang sử dụng EmptyDataDecls để cho GHC làm việc đó cho tôi.Tuyên bố dữ liệu rỗng đáng yêu

Điều tôi cần là con trỏ đến một trong các loại dữ liệu này, nhưng khi tôi cố tạo một kiểu với alloca, nó sẽ than phiền rằng dữ liệu không thuộc loại Storable. Ví dụ:

{-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls #-} 

module Main where 

import Foreign.Marshal.Alloc 
import Foreign.Ptr 

data Struct 

foreign import ccall "header.h get_struct" 
    get_struct :: Ptr Struct -> IO() 

main = alloca $ \ptr -> get_struct ptr 

GHC sẽ không biên dịch điều này, không có trường hợp nào cho số Storable Struct. Tôi có thể tự mình thực hiện:

instance Storable Struct where 
    sizeOf _ = ... 
    alignment _ = ... 

Nhưng điều đó gần như đánh bại mục đích - tôi không muốn phải xác định những điều như vậy nếu tôi không quan tâm đến cấu trúc.

Tôi nhận thấy rằng con trỏ trỏ đến hoạt động tốt, vì lớp PtrStorable. Vì vậy, tôi có thể thực hiện những gì tôi đang nhắm đến bằng cách sử dụng peek trên ptr trước khi gọi get_struct:

main = alloca $ \ptr -> do 
    ptr <- peek ptr 
    get_struct ptr 

này cảm thấy giống như một hack, mặc dù.

Có cách nào để nhận các khai báo dữ liệu trống để được coi là Storable mà không định nghĩa một cá thể không?

+2

Đây là một hack. Bạn không bao giờ phân bổ không gian cho con trỏ bên trong; bạn chỉ đang trỏ vào bộ nhớ ngẫu nhiên. Cách này nằm segfaults. –

+0

Vì vậy, nếu tôi hợp pháp muốn một con trỏ đến một con trỏ, tôi nên sử dụng hai 'alloca' cuộc gọi và sau đó' poke' một con trỏ vào khác, phải không? – zmthy

+0

có (hoặc sử dụng một số hình thức phân bổ khác). Việc sử dụng phổ biến nhất cho một con trỏ tới một con trỏ là con trỏ ra các giá trị, trong trường hợp đó hàm ràng buộc làm cho việc phân bổ và các mảng của chuỗi (nghĩ 'argv'). Th –

Trả lời

6

Bạn không thể phân bổ điều gì đó nếu bạn không biết nó lớn đến cỡ nào. Có phải chức năng sẽ bỏ qua đối số của nó? Sau đó vượt qua trong một con trỏ null. Nếu không, bạn cần thực sự phân bổ đủ không gian cho cấu trúc - không cắt góc bằng cách cấp phát bộ đệm có kích thước bằng 0 byte hoặc con trỏ, khi đó hàm được gọi sẽ ghi qua phần cuối bộ đệm của bạn, làm hỏng bộ nhớ.

Hoặc kết thúc khai báo dữ liệu hoặc viết một trường hợp đáng yêu với các giá trị kích thước và căn chỉnh phù hợp; không có cách nào xung quanh việc cung cấp dữ liệu kích thước/căn chỉnh ở một dạng nào đó.

+2

Bạn có thể sử dụng một công cụ thuận tiện như chs cho mục đích này - nó giúp bạn tìm ra các giá trị này. – fuz

+3

Lưu ý rằng bạn không phải xác định mọi phương thức của một cá thể. Nếu bạn không muốn sắp xếp các cấu trúc cho Haskell, chỉ xác định 'sizeOf' và' alignment' nhưng để lại 'peek' và' poke' undefined (hoặc lỗi cuộc gọi). –

2

Đây là một cách tiếp cận khác có thể phù hợp với bạn. Tôi giả sử rằng bạn có quyền truy cập vào tất cả các tệp tiêu đề C xác định các đối tượng bạn cần phân bổ. Nếu đó là sự thật, bạn có thể viết một lớp mã C nhỏ để phân bổ và giải phóng các đối tượng C. Mã Haskell của bạn sau đó có thể gọi các hàm C này mà không cần mã Haskell cần biết những gì đằng sau các con trỏ. Haskell cũng có thể tự động gọi mã miễn phí khi bộ thu gom rác của Haskell biết rằng các đối tượng không còn cần thiết nữa.

Các vấn đề liên quan