代码中的函数fac与reverse及样板代码的相关知识

#include   
#include   
#include <string.h>  
  
int fac(int n) { if (n < 2) return(1); /* 0! == 1! == 1 */ return (n)*fac(n-1); /* n! == n*(n-1)! */ } char *reverse(char *s) { register char t, /* tmp */ *p = s, /* fwd */ *q = (s + (strlen(s) - 1)); /* bwd */ while (p < q) /* if p < q */ { t = *p; /* swap & move ptrs */ *p++ = *q; *q-- = t; } return(s); } int main() { char s[BUFSIZ]; printf("4! == %d\n", fac(4)); printf("8! == %d\n", fac(8)); printf("12! == %d\n", fac(12)); strcpy(s, "abcdef"); printf("当我们反转“abcdef”时,我们得到“%s”。", \ reverse(s)); strcpy(s, "madam"); printf("将“madam”进行反转,我们得到“%s”。", \ reverse(s)); return 0; } 

代码中的函数fac与reverse及样板代码的相关知识

上述代码包含两个函数,一个函数是 fac(),它用于递归求阶乘;另一个是 reverse()函数,此函数实现了一个简单的字符串反转算法,其主要作用是对传入的字符串进行修改,让其内容完全反转,并且不需要采用申请内存后反着复制的方式。

(2)用样板来包装代码

接口的代码被称作“样板”代码。它是应用程序代码与 Python 解释器进行交互时不可或缺的一部分。4. 要增加模块初始化函数 void initModule()。

#include   
#include   
#include <string.h>  
  
int fac(int n) { if (n < 2) return(1); return (n)*fac(n-1); } char *reverse(char *s) { register char t, *p = s, *q = (s + (strlen(s) - 1)); while (s && (p < q)) { t = *p; *p++ = *q; *q-- = t; } return(s); } int test() { char s[BUFSIZ]; printf("4! == %d\n", fac(4)); printf("8! == %d\n", fac(8)); printf("12! == %d\n", fac(12)); strcpy(s, "abcdef"); printf("reversing 'abcdef', we get '%s'\n", \ reverse(s)); strcpy(s, "madam"); printf("reversing 'madam', we get '%s'\n", \ reverse(s)); return 0; } #include "Python.h" static PyObject *Extest_fac 作用于两个参数,一个是 PyObject 类型的 self,另一个是 PyObject 类型的另一个参数。args) { int num; if (!PyArg_ParseTuple(args, "i", &num)) return NULL; 使用 Py_BuildValue 函数来返回一个 PyObject* 类型的值。"i", fac(num)); } static PyObject *Extest_doppel 作用于 PyObject *self 和 PyObject *另一个对象,在这个过程中进行某种操作或处理,以达到特定的功能或效果。args) { char *orig_str; char *dupe_str; PyObject* retval; if (!PyArg_ParseTuple(args, "s", &orig_str)) returnretval 等于 (PyObject*)Py_BuildValue( 。"ss", orig_str, dupe_str=reverse(strdup(orig_str))); free(dupe_str); #防止内存泄漏 return retval; } static PyObject *Extest_test 函数,它的参数为 PyObject *self 和 PyObject *另一个参数。args) { test(); return (PyObject*)Py_BuildValue(""); } static PyMethodDef ExtestMethods[] = { { "fac"Extest_fac 以及 METH_VARARGS 。"doppel"Extest_doppel 和 METH_VARARGS 包含在其中。"test"Extest_test 以及 METH_VARARGS 等内容,还有 { NULL, NULL } 等。void initExtest() { Py_InitModule("Extest", ExtestMethods); } 

Python.h 头文件在很多类 Unix 系统里,要么在 /usr/local/include/python2.x 目录,要么在 /usr/include/python2.x 目录。系统通常能够知晓文件的安装路径。

创建一个名为 Extest_fac()的包装函数,若要在 Python 脚本中使用该包装函数,需先 import Extest,接着调用 Extest.fac()。当 Extest.fac()被调用时,会触发包装函数 Extest_fac()的调用。此包装函数接受一个 Python 的整数参数,将其转换为 C 的整数,然后调用 C 的 fac()函数,获取一个整型的返回值,最后把该返回值转换为 Python 的整型数,作为整个函数调用的结果返回。另外两个包装函数,即 Extest_doppel()和 Extest_test(),它们的情况是类似的。

用 PyArg_Parse*系列函数进行从 Python 到 C 的转换。其中,int PyArg_ParseTuple()用于把 Python 传过来的参数转为 C。int PyArg_ParseTupleAndKeywords()的作用和 PyArg_ParseTuple()相同,不过它能同时解析关键字参数。它们的用法类似 C 的 sscanf 函数,都接受一个字符串流,依据指定的格式字符串进行解析,然后将结果放入相应指针所指的变量中。它们的返回值为 1 时表示解析成功,返回值为 0 时表示失败。PyObject* Py_BuildValue()是从 C 到 Python 的转换函数,它能把 C 的数据转为 Python 的一个对象或一组对象并返回;Py_BuildValue 的用法与 sprintf 相似,会将所有参数按格式字符串所指定的格式转换成一个 Python 的对象。

C与Python之间数据转换的转换代码:

为每个模块添加一个数组,其型如 PyMethodDef ModuleMethods[]。这样做的目的是让 Python 解释器能够导入并调用这些数组。每个数组都包含了函数在 Python 中的名字、相应包装函数的名字以及一个 METH_VARARGS 常量。METH_VARARGS 意味着参数是以 tuple 形式传入的。若要使用 PyArg_ParseTupleAndKeywords()函数来分析命名参数,就需让该标志常量与 METH_KEYWORDS常量进行逻辑与运算。数组以两个 NULL 来表示函数信息列表的结束。

模块的初始化函数是所有工作的最后一部分。需要调用 Py_InitModule()函数,同时把模块名和 ModuleMethods[]数组的名字传递进去,这样解释器就能正确地调用模块中的函数。

(3)编译

为了创建新的 Python 扩展,需要将它们与 Python 库一起进行编译。distutils 包可用于编译、安装和分发这些模块、扩展以及包。

创建一个名为 setup.py 的文件,其中最主要的工作是由 setup()函数来完成的。

#!/usr/bin/env python  
  
from distutils.core import setup, Extension  
  
MOD = 'Extest'设置名称为 MOD,扩展模块为[Extension(MOD, 源文件=['Extest2.c'])]) 

Extension 的第一个参数是扩展的名字,若模块是包的一部分,需加上用 '.' 分隔的完整包的名字。上述扩展是独立的,所以名字只需写“Extest”。sources 参数是所有源代码的文件列表,其中只有一个文件为 Extest2.c。setup 有两个参数,一个是名字参数,它用于表示要编译的内容;另一个是列表参数,该参数用于列出要编译的对象。因为上述要编译的是一个扩展,所以将 ext_modules 参数的值设为扩展模块的列表。

运行 setup.py build 命令,就能够开始对我们的扩展进行编译,会有部分信息被提示:

创建 build/lib.linux-x86_64-2.6 这个东西。  构建出 build/lib.linux-x86_64-2.6 。  做出 build/lib.linux-x86_64-2.6 。  生成 build/lib.linux-x86_64-2.6 。  形成 build/lib.linux-x86_64-2.6 。  产出 build/lib.linux-x86_64-2.6 。  制造出 build/lib.linux-x86_64-2.6 。  得到 build/lib.linux-x86_64-2.6 。  开发出 build/lib.linux-x86_64-2.6 。  设计出 build/lib.linux-x86_64-2.6 。  筹备出 build/lib.linux-x86_64-2.6 。  规划出 build/lib.linux-x86_64-2.6 。  安排出 build/lib.linux-x86_64-2.6 。  准备好 build/lib.linux-x86_64-2.6 。  预备出 build/lib.linux-x86_64-2.6 。  筹备起 build/lib.linux-x86_64-2.6 。  规划起 build/lib.linux-x86_64-2.6 。  安排起 build/lib.linux-x86_64-2.6 。  准备构建 build/lib.linux-x86_64-2.6 。  预备构建 build/lib.linux-x86_64-2.6 。  筹备进行 build/lib.linux-x86_64-2.6 。  规划进行 build/lib.linux-x86_64-2.6 。  安排进行 build/lib.linux-x86_64-2.6 。  开始构建 build/lib.linux-x86_64-2.6 。  着手构建 build/lib.linux-x86_64-2.6 。  启动构建 build/lib.linux-x86_64-2.6 。  开启构建 build/lib.linux-x86_64-2.6 。  发动构建 build/lib.linux-x86_64-2.6 。  促使构建 build/lib.linux-x86_64-2.6 。  推进构建 build/lib.linux-x86_64-2.6 。  推动构建 build/lib.linux-x86_64-2.6 。  引领构建 build/lib.linux-x86_64-2.6 。  引导构建 build/lib.linux-x86_64-2.6 。  指导构建 build/lib.linux-x86_64-2.6 。  辅导构建 build/lib.linux-x86_64-2.6 。  辅助构建 build/lib.linux-x86_64-2.6 。  协助构建 build/lib.linux-x86_64-2.6 。  帮忙构建 build/lib.linux-x86_64-2.6 。  助力构建 build/lib.linux-x86_64-2.6 。  促进构建 build/lib.linux-x86_64-2.6 。  鼓动构建 build/lib.linux-x86_64-2.6 。  激发构建 build/lib.linux-x86_64-2.6 。  引发构建 build/lib.linux-x86_64-2.6 。  诱使构建 build/lib.linux-x86_64-2.6 。  驱使构建 build/lib.linux-x86_64-2.6 。  催动构建 build/lib.linux-x86_64-2.6 。  策动构建 build/lib.linux-x86_64-2.6 。  鼓动起构建 build/lib.linux-x86_64-2.6 。  激发起构建 build/lib.linux-x86_64-2.6 。  引发起构建 build/lib.linux-x86_64-2.6 。  
gcc 进行编译操作,使用了 -pthread 参数,还进行了共享库的构建,构建的对象文件是 build/temp.linux-x86_64-2.6/Extest2.o ,链接时指定了库路径 -L/usr/lib64 ,链接的库是 -lpython2.6 ,最终生成的共享库文件是 build/lib.linux-x86_64-2.6/Extest.so

(4)导入和测试

你的扩展会被创建在运行 setup.py 脚本的目录下的 build/lib.* 目录里。你可以切换到那个目录去测试模块,也可以使用命令“python setup.py install”将其安装到 Python 中,此过程会提示相应信息。

测试模块:

(5)引用计数和线程安全

并且,Py_INCREF()和 Py_DECREF()这两个函数还有先检查对象是否为空的版本,分别是 Py_XINCREF()和 Py_XDECREF()。

编译扩展的程序员需要注意,代码有可能在多线程的 Python 环境中运行。这些线程使用了 Py_BEGIN_ALLOW_THREADS 和 Py_END_ALLOW_THREADS 这两个 C 宏。通过将代码与线程隔离,能保证运行和非运行时的安全性。由这些宏包裹的代码将会允许其他线程运行。

你可能想看:
« 上一篇
下一篇 »

相关推荐

python爬虫教程PDF,Python爬虫书PDF

2026年09月02日

32阅读

外国教程python,python编程教学视频

2026年09月02日

27阅读

python简明教程沈洁元,python详细基础教程

2026年09月02日

21阅读

python库包教程,python 包

2026年09月02日

27阅读

python教程大全集,python教程600集

2026年09月02日

27阅读

python入门教程完整版,python零基础入门全套教程视频

2026年09月02日

23阅读