Chinaunix首页 | 论坛 | 博客

分类: Python/Ruby

2014-04-12 00:28:31

返回值


    返回值类型跟函数的参数类型一样,可以有多种情况。在上一篇介绍指针的类型时,我试图利用pi=lib.add(pi)的形式,接收函数返回的指针。结果pi的类型转变为。正确的处理方式是什么? 就在这篇文章从总结一下吧。
    函数一般返回
c_int类型,其它的返回类型可以通过设置function对象的restype属性。 如下所示例:

>>> pi = pointer(c_int())      

>>> lib.add.restype = type(pi)                   //type函数还是很有用的嘛!

>>> pi=lib.add( pointer(c_int(1000))  )

>>> pi

<__main__.LP_c_long object at 0xa04a4f4>

>>> pi.contents

c_long(1100)

         仍然要注意pi访问属性contents时,会将对象复制一份。
    另一个例子:
           >>> strchr = libc.strchr 


>>> strchr("abcdef", ord("d"))

8059983( 返回的内容为 

>>> strchr.restype = c_char_p      # c_char_p is a pointer to a string 

>>> strchr("abcdef", ord("d"))         #返回的类型为 ? 这是为什么?

'def'          

>>> print strchr("abcdef", ord("x")) 

None          //返回指针为NULL

>>> 

 

Python内置对象直接作为函数的数据类型

    针对上面的疑问解释如下:
        >>> libc.printf("%s\n", "123")
        123
        4
    按说我们应该传递一个c_char_p类型的数据结构,但是实际传递的是内置类型。
    王八的屁股,规定:None、 可直接作为函数的参数,对应关系分别是NULL,c_int、c_long、c_char_p
   有了这个,就可解释的通了。

函数参数的安全行检查:

    基本数据类型、数组、指针、引用作为参数和返回值的情况,我们也都分析过了。接下来,按说应该是struct/class这个主题。在分析这个主题之前,介绍自己做实验中碰到的问题和解决办法。即,函数参数的安全性检查。
    >>> libc.printf("%d","11111111111")
    1682606929
    以上调用也能顺利执行,这不是瞎搞嘛! Python提供如下的机制。它允许设置argtypes属性,它描述了函数的每个参数的类型
>>> strchr.restype = c_char_p 
>>> strchr.argtypes = [c_char_p, c_char] 
>>> strchr("abcdef", "d") 
'def' 
>>> strchr("abcdef", "def")          //这里体现了安全性检查
Traceback (most recent call last): 
  File "", line 1, in ? 
ArgumentError: argument 2: exceptions.TypeError: one character string expected 
>>> print strchr("abcdef", "x") 
None 

        你可以使用一个可调用的
python对象(一个函数或者一个class,一切皆对象)作为这restype属性的值,如果外部函数返回的是一个整数这个可调用对象将调用这C函数返回的整数这个可调用对象的结果将作为这个函数调用的结果,这个对于检查 返回值,同时产生一个错误很有帮助。
>>> GetModuleHandle = windll.kernel32.GetModuleHandleA # doctest: +WINDOWS 
>>> def ValidHandle(value):          //value是整数
...     if value == 0: 
...         raise WinError() 
...     return value 

>>> 
>>> GetModuleHandle.restype = ValidHandle
>>> GetModuleHandle(None)  
486539264 
>>> GetModuleHandle("something silly")
Traceback (most recent call last): 
  File "", line 1, in ? 
  File "", line 3, in ValidHandle 
WindowsError: [Errno 126] The specified module could not be found. 
>>> 


类型可变与不可变:

      对于非指针类型:c_int、c_long、c_double 这些类型是可变的,他们的值在后面也是可以改变的。 例如:xx.value=10。    

      对于指针类型?肯定也是可变的类型。分配一个新值到这些指针类型c_char_p, c_wchar_p, c_void_p的一个实例上,改变它们指向的 内存位置,而不是这些内存块的内容。所以可变指的是指针可变,它指向的内容可变吗?不要期望传给函数的指针是指向可变的内存。如果你需要可变的内存块,ctypes有一个 create_string_buffer 函数。这内存块内容通过这raw属性来访问或改变,如果你想访问一个以null结束 的字符串,使用这string属性 

>>> libc.strcat.restype=c_char_p

>>> c="1234567"

>>> a="123"

>>> libc.strcat(c,a)

'123456723212321123'             //得到的结果是错误的。

>>> c=create_string_buffer("1234567",30)

>>> a=create_string_buffer("123",30)

>>> print repr(c.raw)

'1234567\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

>>> libc.strcat(c,a)

'1234567123'              //得到的结果是正确的

>>> c.raw

'1234567123\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

这种方法应该也行:(c_char * 10)()

阅读(2176) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~