2012-02-03 27 views
5

Tôi đang cố gắng viết trình bao bọc cho một thư viện gốc trong Linux. Vấn đề là thế này:python ctypes gửi con trỏ tới cấu trúc làm tham số cho thư viện gốc

định nghĩa trong c:

int mymethod(mystruct* ptr)

trong python:

_lib.mymethod.argtypes = (ctypes.POINTER(mystruct),)
_lib.mymethod.restype = ctypes.c_int

s = mystruct()

_lib.mymethod(ctypes.byref(s))
tăng lương : Dự kiến ​​LP_mystruct dụ thay vì con trỏ đến mystruct

_lib.mymethod(ctypes.pointer(s))
tăng dự kiến ​​dụ LP_mystruct thay vì LP_mystruct

lỗi. Làm thế nào để vượt qua một cấu trúc như một con trỏ đến một phương pháp bản địa?

Cảm ơn.

Mete

Trả lời

5

Vấn đề là mức độ cao hơn "con trỏ" từ ctypes, trong Python, một đối tượng khác với "một con trỏ chung chung" (ctypes.CArgObject bởi ctypes.byref) được trả lại hoặc một số duy nhất đại diện cho một ký ức địa chỉ (đó là những gì được trả về bởi CType của adrresof) - bạn có thể chú thích chức năng của bạn để nhận một `ctypes.c_voidp và gọi nó với _lib.mymethod(ctypes.addressof(a)) thay -

Hoặc nếu bạn muốn làm việc ở phía bên stronged đánh máy để tránh các lỗi sẽ crash Python (một lỗi kiểu làm tăng một ngoại lệ Python) - một tham số sai được truyền cho một C uncti trên sẽ gây ra lỗi phân đoạn trên trình thông dịch Python), bạn phải tạo biến để giữ "loại" mới là POINTER cho cấu trúc của bạn - và sau đó tạo một thể hiện loại này với địa chỉ cấu trúc của bạn:

mystruct_pointer = ctypes.POINTER(mystruct) 
_lib.mymethod.argtypes = (mystruct_pointer,) 
_lib.mymethod.restype = ctypes.c_int 

s = mystruct() 

_lib.mymethod(mystruct_pointer.from_address(ctypes.addressof(s))) 
+1

Cảm ơn! Tôi đã sử dụng phương pháp thứ hai mà bạn đã nói và nó hoạt động mà không có vấn đề gì. – mete

+0

một cái gì đó tương tự ở đây - https://codexample.org/questions/238108/python-ctypes-sending-pointer-to-structure-as-parameter-to-native-library.c –

+0

Đó là loại POINTER cấp cao hơn trong ctypes ? –

3

(tôi biết rằng đây là một câu hỏi cũ, nhưng tôi nghĩ câu trả lời được chấp nhận là một workaround không cần thiết, vì vậy tôi muốn để lại điều này ở đây cho hậu thế.)

Trên thực tế ctypes nên explicitly support sử dụng byref() để vượt qua con trỏ như thế:

ctypes xuất khẩu các chức năng byref() được sử dụng để vượt qua các tham số bằng cách tham khảo. Hiệu ứng tương tự có thể đạt được với chức năng pointer(), mặc dù pointer() thực hiện nhiều công việc hơn vì nó xây dựng một đối tượng con trỏ thực, vì vậy nó nhanh hơn để sử dụng byref() nếu bạn không cần đối tượng con trỏ trong chính Python.

Nguyên nhân có thể của việc này là bạn đã xác định cấu trúc của bạn trong hơn một nơi (ví dụ trong các module khác nhau) - nếu việc chuyển nhượng argtypes thấy một định nghĩa và gọi hàm thấy khác, lỗi nhầm lẫn này phát sinh. Nói cách khác, ctypes cố gắng khớp hai loại mystruct (có thể) giống hệt nhau về nội dung và có cùng tên chính xác, nhưng chúng không phải là loại cùng loại.Miễn là loại cấu trúc cơ sở là một đối tượng kiểu đơn, nó không quan trọng nếu bạn xây dựng một con trỏ đến nó bằng cách sử dụng pointer(), byref() hoặc POINTER()() - ctypes sẽ phát hiện rằng kiểu cơ bản (chỉ đến) là giống nhau.

Để xác minh xem đây có phải là trường hợp không, hãy thử assert(_lib.mymethod.argtypes[0]._type_ == type(s)) ngay trước khi gọi chức năng bên ngoài.

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