ctypes - 初学者

时间:2011-02-22 17:54:26

标签: python python-3.x ctypes

我的任务是将c库“包装”到python类中。在这个问题上,文档非常模糊。似乎他们期望只有高级python用户才能实现ctypes。好吧,我是python的初学者,需要帮助。

一步一步的帮助会非常棒。

所以我有我的c库。我该怎么办?我把哪些文件放在哪里?如何导入库?我读到可能有一种方法可以“自动换行”到Python?

(顺便说一下,我在python.net上做了ctypes教程,但它没有用。意思是我认为他们假设我应该能够完成剩下的步骤。

实际上这是我用他们的代码得到的错误:

File "importtest.py", line 1
   >>> from ctypes import *
   SyntaxError: invalid syntax

我真的可以逐步帮助这个!感谢〜

3 个答案:

答案 0 :(得分:190)

这是一个快速而又脏的ctypes教程。

首先,编写C库。这是一个简单的Hello world示例:

testlib.c

#include <stdio.h>

void myprint(void);

void myprint()
{
    printf("hello world\n");
}

现在将其编译为共享库(mac fix found here):

$ gcc -shared -Wl,-soname,testlib -o testlib.so -fPIC testlib.c

# or... for Mac OS X 
$ gcc -shared -Wl,-install_name,testlib.so -o testlib.so -fPIC testlib.c

然后,使用ctypes编写一个包装器:

testlibwrapper.py

import ctypes

testlib = ctypes.CDLL('/full/path/to/testlib.so')
testlib.myprint()

现在执行它:

$ python testlibwrapper.py

你应该看到输出

Hello world
$

如果您已经考虑过库,则可以跳过本教程的非python部分。确保ctypes可以通过将其放在/usr/lib或其他标准目录中来查找库。如果这样做,则在编写包装器时无需指定完整路径。如果您选择不这样做,那么必须在调用ctypes.CDLL()时提供库的完整路径。

这不是更全面的教程的地方,但如果您在本网站上寻求特定问题的帮助,我相信社区会帮助您。

PS:我假设您使用的是Linux,因为您使用过ctypes.CDLL('libc.so.6')。如果你在另一个操作系统上,事情可能会有所改变(或者很多)。

答案 1 :(得分:28)

Chinmay Kanchi的答案很棒,但我想要一个函数的例子,它传递并将变量/数组返回给C ++代码。我虽然在这里包含它,以防它对其他人有用。

传递和返回整数

一个函数的C ++代码,它接受一个整数并将一个加到返回值

extern "C" int add_one(int i)
{
    return i+1;
}

保存为文件test.cpp,请注意required extern“C”(可以删除C代码)。 这是使用g ++编译的,参数类似于Chinmay Kanchi的回答,

g++ -shared -o testlib.so -fPIC test.cpp

Python代码使用load_library中的numpy.ctypeslib,假设共享库的路径与Python脚本位于同一目录中,

import numpy.ctypeslib as ctl
import ctypes

libname = 'testlib.so'
libdir = './'
lib=ctl.load_library(libname, libdir)

py_add_one = lib.add_one
py_add_one.argtypes = [ctypes.c_int]
value = 5
results = py_add_one(value)
print(results)

按预期打印6个。

传递和打印数组

您还可以按如下方式传递数组,以便C代码打印数组元素

extern "C" void print_array(double* array, int N)
{
    for (int i=0; i<N; i++) 
        cout << i << " " << array[i] << endl;
}

以前编译并以相同方式导入。那么使用这个函数的额外Python代码就是

py_print_array = lib.print_array
py_print_array.argtypes = [ctl.ndpointer(np.float64, 
                                         flags='aligned, c_contiguous'), 
                           ctypes.c_int]
A = np.array([1.4,2.6,3.0], dtype=np.float64)
py_print_array(A, 3)

我们指定数组,print_array的第一个参数,作为指向Numpy数组的对齐,c_contiguous 64位浮点数的指针,第二个参数作为一个整数,它告诉C代码中的元素数量Numpy数组。然后由C代码打印如下,

1.4
2.6
3.0

答案 2 :(得分:10)

首先:你在python示例中看到的>>>代码是一种表明它是Python代码的方法。它用于将Python代码与输出分开。像这样:

>>> 4+5
9

在这里,我们看到以>>>开头的行是Python代码,9就是它产生的结果。这正是它启动Python解释器时的样子,这就是为什么这样做的原因

您永远不会将>>>部分输入.py文件。

这会解决您的语法错误。

其次,ctypes只是包装Python库的几种方法之一。其他方法是SWIG,它将查看您的Python库并生成一个公开C API的Python C扩展模块。另一种方法是使用Cython

他们都有利有弊。

SWIG只会将您的C API暴露给Python。这意味着你没有得到任何对象或任何东西,你必须制作一个单独的Python文件。然而,通常有一个名为“wowza”的模块和一个名为“_wowza”的SWIG模块,它是C API的包装器。这是一种很好的简单方法。

Cython生成一个C-Extension文件。它的好处是您编写的所有Python代码都是C语言,因此您编写的对象也使用C语言,这可以提高性能。但是你必须学习它如何与C接口,所以学习如何使用它需要额外的工作。

ctypes的好处是没有可编译的C代码,因此非常适合用于包装由其他人编写的标准库,并且已经存在于Windows和OS X的二进制版本中。