Ctype-初学者

我的任务是将一个 c 库“包装”成一个 python 类。文件对此含糊不清。他们似乎认为只有高级 Python 用户才会实现 ctype。

一步一步的帮助将是美好的。

我有我的 C 库。我该怎么办?我把什么文件放在哪里?如何导入库?我听说有一种方法可以“自动包装”Python?

(顺便说一下,我在 python.net 上做了 ctype 教程,但是没有用。也就是说,我认为他们认为我应该能够完成剩下的步骤。)

事实上,这就是我在他们的代码中得到的错误:

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

我真的需要一些一步一步的帮助!

130293 次浏览

下面是一个快速而肮脏的 ctype 教程。

首先,编写你的 C 语言库,下面是一个简单的 Hello world 示例:

Testlib.c

#include <stdio.h>


void myprint(void);


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

现在将其编译为共享库(在这里找到了 Mac 修复程序) :

$ 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

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

Testlibwrapper.py

import ctypes


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

现在执行它:

$ python testlibwrapper.py

您应该会看到输出

Hello world
$

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

这不是一个更全面的教程的地方,但是如果你在这个网站上寻求具体问题的帮助,我相信社区会帮助你。

附注: 我假设您使用 Linux 是因为您使用了 ctypes.CDLL('libc.so.6')。如果您使用的是另一个操作系统,情况可能会有一点(或相当大)变化。

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

>>> 4+5
9

在这里,我们看到以 >>>开头的行是 Python 代码,结果是9。如果您启动一个 Python 解释器,它看起来就是这样的,这就是为什么要这样做的原因。

永远不要在 .py文件中输入 >>>部分。

可以解决语法错误。

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

它们都有利有弊。

SWIG 将只向 Python 公开您的 CAPI。这意味着您不会得到任何对象或任何东西,您必须创建一个单独的 Python 文件来完成这项工作。然而,通常有一个名为 say“ wowza”的模块和一个名为“ _ wowza”的 SWIG 模块,后者是 C API 的包装器。这是一种既好又简单的做事方式。

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

Ctype 的好处是不需要编译 C 代码,所以用它来包装其他人编写的标准库非常好,而且 Windows 和 OS X 已经有了二进制版本。

Chinmay Kanchi 给出的答案非常好,但是我想要一个函数的例子,它可以将一个变量/数组传递并返回给 C + + 代码。我想我会把它包括在这里,以防它对其他人有用。

传递和返回一个整数

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

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

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

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

Python 代码使用 numpy.ctypeslib中的 load_library,假定到与 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的第一个参数,作为一个指向对齐的 Numpy 数组的指针,c _ 毗连的64位浮点数,第二个参数作为一个整数,告诉 C 代码 Numpy 数组中的元素数。然后用 C 代码打印如下,

1.4
2.6
3.0