2010-08-10 18 views
5

我想了解Python「ctypes」模塊。我已經將一個簡單的例子放在一起 - 理想情況下 - 包裝statvfs()函數調用。代碼如下所示:幫我理解爲什麼我使用Python的ctypes模塊失敗

from ctypes import * 

class struct_statvfs (Structure): 
    _fields_ = [ 
      ('f_bsize', c_ulong), 
      ('f_frsize', c_ulong), 
      ('f_blocks', c_ulong), 
      ('f_bfree', c_ulong), 
      ('f_bavail', c_ulong), 
      ('f_files', c_ulong), 
      ('f_ffree', c_ulong), 
      ('f_favail', c_ulong), 
      ('f_fsid', c_ulong), 
      ('f_flag', c_ulong), 
      ('f_namemax', c_ulong), 
      ] 


libc = CDLL('libc.so.6') 
libc.statvfs.argtypes = [c_char_p, POINTER(struct_statvfs)] 
s = struct_statvfs() 

res = libc.statvfs('/etc', byref(s)) 
print 'return = %d, f_bsize = %d, f_blocks = %d, f_bfree = %d' % (
    res, s.f_bsize, s.f_blocks, s.f_bfree) 

運行此不約而同返回:

return = 0, f_bsize = 4096, f_blocks = 10079070, f_bfree = 5048834 
*** glibc detected *** python: free(): invalid next size (fast): 0x0000000001e51780 *** 
*** glibc detected *** python: malloc(): memory corruption (fast): 0x0000000001e517e0 *** 

我一直沒能找到調用複雜類型作爲參數任何例子(有很多返回複雜類型的函數示例),但在盯着ctypes文檔一天左右之後,我認爲我的調用語法是正確的......它實際上是調用statvfs()調用並獲取正確的結果。

我誤解了ctypes文檔嗎?還是有其他事情在這裏?

謝謝!

+0

我還沒有找到答案,但我可以告訴你,當我將它作爲腳本運行時,你的代碼對我來說工作正常,但是當我在交互式解釋器中運行它時會導致段錯誤。具體來說,它會在一些看似隨機的時間段後,或者解釋器退出時,以先到者爲準,導致段錯誤。我會一直試圖弄清楚這一點,但我認爲這些信息可能會讓問題更容易找到比我更有見識的人。 – 2010-08-10 13:49:16

+1

一個問題可能是您不必定義類struct_statvfs,例如,你的尺寸比libc認爲的要小。運行這個小C程序來驗證:#include int main(){return!printf(「%d \ n」,sizeof(struct statvfs)); } – pts 2010-08-10 13:52:47

+0

錯誤和過時的文檔比沒有文檔更糟糕。我沒有想到看到一個困擾我的結構定義(與statvfs無關)。好事我看到了這個問題。 – ianalis 2010-08-20 16:26:40

回答

4

執行此命令可以在系統上獲得struct statvfs的確切定義:

echo '#include <sys/statvfs.h>' | gcc -E - | less 

然後按/struct statvfs<enter>跳到定義並從那裏瀏覽。

也看看my patch fusepy和their definition

+1

這就是我所信任的手冊頁。感謝您的建議!由於這是我第一次使用ctypes,我不確定故障模式到底意味着什麼。 – larsks 2010-08-10 15:25:24

+0

很酷的捷徑來獲取結構定義。我必須記住這一點。 – Mark 2010-08-10 15:52:40

+0

是的,ctypes被討論了很多,但讓所有東西都被正確定義仍然很痛苦。它確實沒有幫助,C編譯器是必要的。應該有C和其他語言可以相互依賴的官方ABI標準。 – 2010-08-11 02:19:32

2

statvfs的聯機幫助頁指出它使用的結構「大致如下定義」,因此您不一定要將聯機幫助頁的字段列表視爲完整的。

我的猜測是,結構結束後還有額外的結構字段,就像你定義它一樣。這會導致statvfs函數覆蓋結構外部的內存。我提出的問題消失了,我要在我的結構定義添加一個巨大的填充字段的_fields_

("padding", c_int * 1000), 

請記住,我的劇本表現出的問題不同於你的;我有一個段錯誤,而你只是有一些錯誤信息。不過,我猜這是同樣的問題,所以你應該嘗試添加一些填充,看看問題是否仍然存在。

+1

c_int * 6似乎已經足夠了(但是* 1000更安全,* 100應該足夠安全),請參閱Linux上的/usr/include/bits/statvfs.h:struct statvfs包含int __f_spare [6]; – pts 2010-08-10 13:58:53

2

正如Eli所示,查看/usr/include/bits/statvfs.h,您的結構沒有正確定義。

在我的64位的Gentoo系統將是:

class struct_statvfs (Structure): 
    _fields_ = [ 
      ('f_bsize', c_ulong), 
      ('f_frsize', c_ulong), 
      ('f_blocks', c_ulong), 
      ('f_bfree', c_ulong), 
      ('f_bavail', c_ulong), 
      ('f_files', c_ulong), 
      ('f_ffree', c_ulong), 
      ('f_favail', c_ulong), 
      ('f_fsid', c_ulong), 
      ('f_flag', c_ulong), 
      ('f_namemax', c_ulong), 
      ('__f_space', c_int * 6) # you are missing this 
      ] 
0

根據成功pyfuse ctypes的包裝保險絲,下面是用於struct statvfs在Linux上:

class c_statvfs(Structure): 
    _fields_ = [ 
     ('f_bsize', c_ulong), 
     ('f_frsize', c_ulong), 
     ('f_blocks', c_fsblkcnt_t), 
     ('f_bfree', c_fsblkcnt_t), 
     ('f_bavail', c_fsblkcnt_t), 
     ('f_files', c_fsfilcnt_t), 
     ('f_ffree', c_fsfilcnt_t), 
     ('f_favail', c_fsfilcnt_t)] 

更多信息: http://code.google.com/p/fusepy/

+1

可能想看看我提交的包含更正到statvfs的修補程序。 http://code.google.com/p/fusepy/issues/detail?id=26 – 2010-08-10 14:18:54

+0

很好。沒意識到它已經過時了。順便說一句,我注意到fusepy只有一個statfs的鉤子,而不是statvfs。 – 2010-08-10 15:22:02

相關問題