Chinaunix首页 | 论坛 | 博客

分类: LINUX

2014-04-11 00:17:14

      在”Python学习笔记1——安装与运行“一节中,说明了Python的两个特性。可扩展性和可嵌入性。可扩展性,即python调用C/C++函数。 该博客提到了ctypes模块,于是利用help命令查看帮助。 这是它的英文在线帮助文档, 这是翻译过来的中文文档。
     接下来的几篇博文,是自己边看中文文档边思考的的内容。

Python若要调用C函数,它需要提供以下支持:
    1、C函数如何供应用程序调用——动态链接库
   2、Python需要提供参数和返回值的数据类型,应该支持:基本数据类型、struct/class、union、enum;也要支持指针和引用。

加载动态链接库

    调用约定关系到函数参数入栈的方式,每个动态链接库都有它自己的调用约定。使用者在使用动态库的函数时也要保持一致的调用约定。
    Linux系统中动态库的默认调用约定是cdecl,所以它加载动态链接库的方式为:cdll.LoadLibrary("libc.so.6")  . 标准库可以直接给定动态库的名称,那么其它库该如何加载? 以绝对路径作为参数即可。

基本数据类型

    C语言中基本数据类型有:char、short、int 、long、float、double。
   在Python中,对应的数据类型是:c_char、c_short、c_int、c_long、c_float、c_double。 使用以下面的例子对c_XXX类型进行分析:
>>> from ctypes import *
>>> libc=cdll.LoadLibrary("libc.so.6")
>>> printf=libc.printf
>>> printf("%c\n","c")          //虽然有输出结果,但明显出错。这是因为Linux下调用C函数时,不存在数据类型的检查工作
D
2
>>> cc=c_char("c")
>>> printf("%c\n",cc)           //这时才有正确的输出.
c
2
>>> cc.value                        //这是访问c_char的value值
'c'
>>> xxx='K'
>>> cc.value = xxx             //更改c_char类型的值
>>> cc.value
'K'
>>> cc.value='P'
>>> xxx                               //注意,cc.value值得修改不影响原先xxx的值.
'K'

数组、指针和引用

        我们还是以基本数据类型为考虑对象,看一下它们对应的数组、指针和引用该如何表示。
        数组:比如要创建含有10个元素的int类型的数组。步骤一:iArray= c_int *10,iArray是一个数组类型;步骤二:iA=iArray() 生成数组对象实例。
数组中元素的访问方式:
>>> iArray= c_int *10
>>> iA=iArray()
>>> iA[3]=3
>>> for x in range(0,10):
...     print iA[x]
        我们知道:数组和指针是有一定的关系的。下面的函数调用
int add(int num1[])     
{
    return num1[0] + num1[1];
}
>>> lib.add(cA)     //这里无论是int num1[] 或者是 int * num1, 结果都一样。
31
实验发现:.so文件如果修改过,那么简单的再次执行LoadLibrary函数试图加载.so时,没有达到我们想要的结果。只能重新运行python

        指针: C语言定义一个结构的指针只需要利用*即可,Python则仍然使用函数poniters来完成。如下所示:
通过调用ctypes类型的指针函数来创建指针实例 
>>> from ctypes import * 
>>> i=c_int(42)
>>> pi=pointers(i)
>>> pi.contents
c_long(42)
>>> pi.contents = c_int(20)
>>> pi.contents
c_long(20)
>>> i
c_long(42)
        注意:这里并没有改变i的值.  每次查看contents属性时,python会产生一个全新的对象。所以 pi.contents = c_int(20)并没有造成修改i对象,
反而让pi指向了另一个对象,且该对象只能通过pi来访问。
>>> pi=pointer(i)
>>> i
c_long(100)
>>> i.value=100000
>>> pi.contents
c_long(100000)
        那么应用在C函数中是什么效果?
>>> from ctypes import *
>>> lib=cdll.LoadLibrary("/usr/local/lib/yan/return_types_of_values.so")
>>> ci = c_int(100)
>>> ci
c_long(100)
>>> pi=pointer(ci)
>>> lib.add(pi)
200
>>> ci
c_long(200)

补充:指针的类型。

>>> PI = POINTER(c_int)        //从此不需要type(pointer (c_int()) ) .

>>> PI 
 

>>> PI(c_int(42)) 

 

>>> 

>>> null_ptr = POINTER(c_int)() 

>>> print bool(null_ptr) 

False 


        引用:C语言对数据结构的引用,使用&;Python对数据结构的引用,使用byref函数。help(brref)这样写到:only usable as function argument。
所以别妄想在Python中使用byref的返回值。 
>>> cc=c_float(2)
>>> cc.value
2.0
>>> rr=byref(cc)
>>> libc.sscanf("2.2", "%f", rr)
1
>>> cc.value
2.200000047683716
阅读(1233) | 评论(0) | 转发(0) |
0

上一篇:.vimrc 内容详解

下一篇:Python与C混合编程2

给主人留下些什么吧!~~