Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python ctypes结构的解码_Python_Structure_Ctypes - Fatal编程技术网

Python ctypes结构的解码

Python ctypes结构的解码,python,structure,ctypes,Python,Structure,Ctypes,我试图在python中了解ctypes,并且我能够让一些简单的事情正常工作,但是当涉及到解包c结构时,我发现自己遇到了一些困难。我决定要学习这一点,我应该仔细研究一下,虽然我知道套接字标准库实现了gethostbyname\u ex(),但我想我应该尝试使用ctypes和libc.gethostbyname()来实现它 我能够相当轻松地执行libc.gethostbyname(): #!/usr/bin/env python from ctypes import * cdll.LoadLibr

我试图在python中了解ctypes,并且我能够让一些简单的事情正常工作,但是当涉及到解包c结构时,我发现自己遇到了一些困难。我决定要学习这一点,我应该仔细研究一下,虽然我知道套接字标准库实现了
gethostbyname\u ex()
,但我想我应该尝试使用
ctypes
libc.gethostbyname()
来实现它

我能够相当轻松地执行libc.gethostbyname():

#!/usr/bin/env python
from ctypes import *

cdll.LoadLibrary('libc.so.6')
libc = CDLL('libc.so.6')
he = libc.gethostbyname("www.google.com")
但这给了我一个
hostent
数据结构。我认为最好的解包方法是获取c结构并创建一个继承自
ctypes.Structure
的类,因此我提出了这个方法(我在
netdb.h
中找到了
hostent
结构定义):

我不清楚的是我是否正确设置了
h_别名
h_addr_列表
字段,因为每当我试图以数组的形式访问这些字段时,即使是在查找我知道的至少有一个别名和至少一个地址的内容之后的第0个索引处,我得到一个空指针访问
ValueError
异常:

>>> he = hostent(libc.gethostbyname("www.google.com"))
>>> pprint.pprint(he.h_addr_list)
<__main__.LP_c_char_p object at 0xb75dae84>
>>> print he.h_addr_list[0]
Traceback (most recent call last):
  File "/tmp/py2659JxK", line 24, in <module>
    print he.h_addr_list[0]
ValueError: NULL pointer access
he=hostent(libc.gethostbyname(“www.google.com”)) >>>pprint.pprint(he.h_地址列表) >>>打印he.h_地址列表[0] 回溯(最近一次呼叫最后一次): 文件“/tmp/py2659JxK”,第24行,在 打印he.h_地址列表[0] ValueError:空指针访问
欢迎提供任何建议。

您需要定义
gethostbyname
的返回类型:

>>> libc.gethostbyname.restype = POINTER(hostent)
>>> he = libc.gethostbyname("www.google.com")[0]
>>> he.h_aliases[0]
'www.google.com'

另外,
h\u addr\u list
不应声明为
指针(c\u char\u p)
,因为
c\u char\u p
用于以null结尾的字符串。在这种情况下,
POINTER(POINTER(c_ubyte))
会更好,如果是IPv4地址,那么第一个地址将是
he.h_addr_list[0][:4]

谢谢。我如何知道
h\u addr\u列表
h\u别名
数组的长度?对它们调用
len()
不起作用,如果我超出数组的末尾,我会得到一个segfault,而不是一个可捕获的异常。@诵读困难症患者:我认为最后一个条目将为null,你可以通过转换为bool来检查null指针,例如:
如果不是他.h_addr_list[idx]:打印“null”
还有一件事,对于netdb.h中的原型,您如何知道如何将
char**h\u别名设置为
POINTER(c\u char\u p)
char**h\u addr\u list
设置为
POINTER(POINTER(c\u ubyte))
。这仅仅是一个关于c结构使用方式的经验和知识的问题吗?@Dyslexics你不能仅仅从头文件中分辨出来。理想情况下,文档会说明哪些字符串以null结尾。在这种情况下不是这样,但实际上没有其他方法:
h_别名
字符串必须以null结尾,因为没有其他方法来确定它们的长度。和
h_addr_list
项不能以空结尾,因为它们可能包含零,因此您可以使用
h_length
字段来指定长度。一般来说,可读字符串在C API中通常以null结尾,而二进制数据则不会。我还有一些关于错误检查的问题,但我将为他们提出一个新的问题,这样如果你回答了这个问题,你就可以获得某种信任。谢谢你的帮助。仅供参考,我生成的代码保存在。
>>> libc.gethostbyname.restype = POINTER(hostent)
>>> he = libc.gethostbyname("www.google.com")[0]
>>> he.h_aliases[0]
'www.google.com'