2014-09-26 96 views
4

我用tcp發送數據到python服務器。數據是這樣的:如何結構解壓C空字符串結束?

struct protocol 
{ 
    unsigned char prot; 
    int id; 
    char name[32]; 
} 

看那name領域,它是一個空結束的字符串,最大尺寸爲32。現在我用strcpy

protocol p; 
memset(&p, 0, sizeof(p)); 
strcpy(name, "abc"); 

現在我使用python解壓縮它。

prot,id,name = struct.unpack("@Bi32s") 

現在len(name)是32,但我需要得到​​字符串時長爲3

我怎麼能這樣做?

回答

1

與解包後空字符('\0')分區它:

>>> prot, id, name = struct.unpack('@Bi32s', b'\0\0\0\0\0\0\0\0abc' + b'\0' * 29) 
>>> name, _, _ = name.partition('\0') 
>>> name 
'abc' 

使用ctypes備選:

>>> from ctypes import * 
>>> 
>>> class Protocol(Structure): 
...  _fields_ = [("prot", c_char), 
...     ("id", c_int), 
...     ('name', c_char * 32)] 
... 
>>> # sock.recv_into(buf) in real program 
... buf = create_string_buffer(b'\0\0\0\0\0\0\0\0abc' + b'\0' * 29) 
>>> p = cast(buf, POINTER(Protocol)) 
>>> p[0].name 
'abc' 
+0

謝謝,這很有幫助。 – tjhack 2014-09-26 13:10:25

+0

@tjhack,我更新了答案。一探究竟。 – falsetru 2014-09-26 13:42:27

1

只要拿到串到第一\0

prot,id,name = struct.unpack("@Bi32s") 
name= name[:name.index("\0")] 

這具有特殊性如果沒有\0出現在字符串內,它將檢查並失敗(拋出ValueError)。

+0

謝謝,解決這個問題的另一種方法 – tjhack 2014-09-26 13:11:46

5

後拆包,你可以做一個:

name = name.split('\0', 1)[0] 

另外,您可以使用​​模塊:

name = ctypes.create_string_buffer(name).value 
+0

我會這樣做:'name = name.split('\ 0',1)[0]' – falsetru 2014-09-26 13:16:23

+0

+1我認爲這可能是最可讀的方式。這可能不如falsetru或我的答案那樣高效,但對於32個字符長的內容,可能無所謂 – goncalopp 2014-09-26 13:17:47

+0

@falsetru:是的,添加一個'maxsplit'參數可以使它稍微高效一些(這是一個很好的建議,謝謝)。 – martineau 2014-09-26 13:20:46

0

如何使用rstrip去除填充?

prot,id,name = struct.unpack("@Bi32s") 
name = name.rstrip(b'\0') 

這也可以讓你使用所有的32個字節來存儲沒有零終止符的名字。但是,這取決於所有填充字節被設置爲零。