ctypes-初学者


100

我的任务是将ac库“包装”到python类中。在这个问题上,文档令人难以置信。看来他们希望只有高级python用户才能实现ctypes。好吧,我是python的初学者,需要帮助。

一些逐步的帮助将是很棒的。

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

(通过我在python.net上进行ctypes教程的方式,它不起作用。这意味着我认为他们认为我应该能够完成其余步骤。

实际上,这是我使用其代码得到的错误:

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

我真的可以为此使用一些逐步的帮助!谢谢〜


10
>>> 在importtest.py中有吗?人们发布>>> 每行都有的代码时,表示该代码正在交互式外壳程序中运行。要从文件中运行它,请删除>>> 它出现的位置(即3>符号和一个空格)。
2011年

4
不要输入>>>s。这些是由交互式外壳程序打印的,应保留在源文件之外。
nmichaels 2011年

8
>>>在.py文件中!哎哟!从来没有见过!
David Heffernan'2

3
老实说,在开始使用ctypes之前,请学习一些Python(至少是一点点)。您永远不会找到假设您不了解基本Python的ctypes教程。
2011年

3
@spentak:如果您需要帮助,请提供足够的信息。至少向我们展示您正在谈论的代码的最新版本。例如,“第3行”上的内容是什么?
Francesco

Answers:


228

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

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

测试库

#include <stdio.h>

void myprint(void);

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

现在将其编译为共享库(可在此处找到macfix):

$ 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
// @ Chinmay:我可以为Windows使用类似的代码,而不是C,请提供一个直观的c ++示例吗?我可以加载我的库,但是无法从.dll文件访问我的函数。它总是说“找不到功能'xyz'”。您能建议我解决这个问题的方法吗?干杯。
Neophile 2011年

我对Windows开发不是很了解,但是Windows看起来有些奇怪,也许它使用了不同的调用约定?也许您可能会查找使用“ extern C”导出C ++函数的方法?
Chinmay Kanchi 2011年

是的,我确实做到了,但到目前为止还没有运气。
Neophile 2011年

6
感谢您易于操作的教程,该教程显示了ctype的基本功能
okysabeni 2012年

1
快速又肮脏总是最好的教程
lurscher

55

Chinmay Kanchi的答案很好,但是我想要一个传递和返回变量/数组到C ++代码的函数示例。我会在这里包括它,以防它对其他人有用。

传递并返回整数

该函数的C ++代码采用整数并将其加到返回值中,

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

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

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

Python代码使用load_librarynumpy.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代码将是,

import numpy as np

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,作为指针对齐,c_contiguous 64个浮点的numpy的阵列,第二个参数为一个整数,它告诉C代码numpy的数组中的元素数目。然后通过C代码如下打印,

1.4
2.6
3.0

5
这是一个很好的补充答案
不好意思,

不知道它是否太明显,但是代码中有错误。它不见了import numpy as np。否则它将无法找到np.float64和其他东西。

@Ben,好地方,在
Ed Smith

11

首先:>>>您在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-扩展文件。这样做的好处是,您编写的所有Python代码都使用C语言编写,因此编写的对象也都使用C语言编写,这可以提高性能。但是您必须学习它与C的接口,因此要学习如何使用它还需要做一些额外的工作。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.