블로거는 개인이나 조직에게 블로거의 원본 기사를 재인쇄하도록 승인하지 않았습니다. 원본에 대한 지원에 감사드립니다!
블로거 링크
저는 국제적으로 유명한 단말기 제조업체에서 근무하며 모뎀 칩 연구 및 개발을 담당하고 있습니다.
5G 초기에는 단말 데이터 비즈니스 레이어와 코어 네트워크 관련 개발 업무를 담당했으며, 현재는 6G 컴퓨팅 네트워크 기술 표준 연구를 주도하고 있다.
블로그 콘텐츠는 주로
5G/6G 프로토콜 설명,
컴퓨팅 파워 네트워크 설명(클라우드 컴퓨팅, 엣지 컴퓨팅, 터미널 컴퓨팅),
고급 C 언어 설명,
Rust 언어 설명 에 중점을 둡니다.
기사 디렉토리
C 언어와 Python 간의 상호 운용성에 대한 자세한 설명
공식 문서 소개: https://docs.python.org/zh-cn/3/extending/index.html
Python은 일부 시스템의 표준 헤더에 영향을 미치는 일부 전처리기 정의를 정의할 수 있으므로 표준 헤더가 포함되기 전에 해당 정의가 포함되어야 합니다
#include<Python.h>
. 그리고 항상 Python.h보다 먼저 정의하는 것이 좋습니다#define PY_SSIZE_T_CLEAN
.
1. Python 구현 방법을 호출하는 C 언어
1.1 호출 프로세스
- C 언어 데이터를 Python 형식으로 변환합니다.
- 변환된 데이터를 사용하여 Python 인터페이스에 대한 함수 호출을 실행합니다.
- 호출로 반환된 데이터를 Python에서 C 형식으로 변환합니다.
1.2 주요 구조 및 기능 소개
Python 환경을 초기화하려면 다음 함수를 사용하십시오.
PyConfig_InitPythonConfig() # 初始化一个PyConfig对象
PyConfig_Read() # 读取当前环境的配置信息
Py_InitializeFromConfig() # 使能客制化的Python环境
중요한 구조 다이어그램 중 하나는 PyConfig
여러 주요 속성의 의미가 다음과 같다는 것입니다.
- module_search_paths_set # 다음 변수는 1로 설정된 경우에만 적용됩니다.
- module_search_paths #지정된 검색 경로 추가
1.3 간단한 Python 문 실행
다음 함수를 사용하여 간단한 Python 문을 실행할 수 있습니다.
# 执行字符串参数中的Python语句
PyRun_SimpleString()
#例如:
PyRun_SimpleString("import sys")
1.4 파일에서 Python 문 실행
다음 함수를 사용하여 파일에서 Python 문을 실행합니다.
# 执行字符串参数中的Python语句
PyRun_SimpleFile()
# 例如:
FILE *fp = fopen("path/to/main.py", "r")
PyRun_SimpleFile(fp, "path/to/main.py")
1.5 Python 모듈 로딩 및 라이브러리 함수 호출
Python 모듈을 로드하고 모듈에서 함수를 호출하는 방법은 다음과 같습니다.
PyImport_ImportModule() # 加载指定的Python模块
PyObject_GetAttrString() # 获取模块中的函数或者成员
PyCallable_Check() # 检测获取的模块对象是否可以调用
PyTuple_New() # 当从C调用Python函数的时候,入参必须使用元组封装,此函数创建一个元组对象
PyObject_CallObject() # 调用Python函数
1.6 C 언어 데이터 유형과 Python 데이터 유형 간의 변환
공식 웹사이트 API를 참조하세요: https://docs.python.org/zh-cn/3/c-api/stable.html
요약된 명명 규칙은 다음과 같습니다.
- Python 데이터 유형을 C 언어 데이터 유형
Py<Python 유형>_As<C 언어 데이터 유형> 으로 변환 - C 언어 데이터 유형을 Python 데이터 유형
Py<Python 유형>_From<C 언어 데이터 유형> 으로 변환
1.7 Python 데이터 객체 생성 및 내장 함수 사용
- Python에서 데이터 유형을 사용하려면 공식 웹 사이트에서
Py<Python type>_XXX를 찾을 수 있습니다. - Python 내장 기능을 사용하려면
Py<Python 기본 라이브러리>_XXX를 찾으면 됩니다.
2. Python은 C 언어 구현 방법을 호출합니다.
2.1 호출 프로세스
- C 언어 데이터 유형을 Python 형식으로 변환합니다.
- 변환된 데이터를 사용하여 Python 인터페이스에 대한 함수 호출을 실행합니다.
- 호출로 반환된 데이터를 Python에서 C 언어 형식으로 변환합니다.
2.2 C 함수를 모듈로 패키징
C 변수와 메소드를 클래스로 캡슐화한 다음(모듈 수준 메소드를 정의할 수도 있음), 이를 모듈로 패키징하고 게시해야 합니다.그러면 Python은 C 함수를 사용할 수 있습니다. 두 가지 주요 데이터 구조가 아래에 소개됩니다.
-
PyModuleDef
- m_base : 기본 클래스이며, 항상 PyModuleDef_HEAD_INIT여야 합니다.
- m_name : 모듈 이름
- m_size : 현재 -1로 설정되어 있으며 일부 고급 사용법에서는 이 매개변수를 사용합니다.
- m_methods : 모듈 메소드 목록
-
PyMethodDef
- ml_name : Python에서 표시되는 메서드 이름
- ml_meth : 해당 C 함수 이름
- ml_flags : 함수에 매개변수가 있는지 여부를 나타냅니다.
2.3 클래스를 정의하는 방법
클래스를 정의하는 주요 데이터 유형은 PyTypeObject
일부 클래스 속성이 이 유형으로 정의된다는 것입니다.
- tp_name : 클래스 이름(형식은 modulename.classname)
- tp_basicsize : 공간을 할당하는 데 사용되는 클래스의 크기
- tp_itemsize : 정적 클래스인 경우 0, 동적 클래스인 경우 0이 아닙니다.
- tp_flags : 클래스의 속성 매개변수는 최소한 Py_TPFLAGS_DEFAULT 여야 합니다.
- tp_new : 클래스의 인스턴스화 함수
- tp_init : 클래스의 초기화 프로그램
- tp_dealloc : 클래스의 소멸자
- tp_members : 회원 목록
- tp_methods : 메소드 목록 (구조는 모듈과 동일)
- tp_getset : 속성 가져오기 및 설정 함수
멤버 정의를 포함하는 구조 PyMemberDef
, 핵심 멤버의 의미:
- name : Python에 표시되는 멤버 이름
- 유형 : 회원 유형
- offset : 구조체에 있는 멤버의 오프셋입니다. offset() 함수를 사용하여 구합니다.
속성의 get 및 set 메소드 구조 PyGetSetDef
와 주요 멤버의 의미를 정의합니다.
- name : Python에서 표시되는 속성의 이름
- get , set : 해당 속성의 get 및 set 메소드
2.4 모듈의 주요 기능 정의
우리가 정의한 모듈이 Python에서 호출되면 PyMODINIT_FUNC PyInit_<moduleName>(void)
함수가 호출됩니다. 간단한 PyInit_(void) 구현 프로세스는 다음과 같습니다:
PyType_Ready()
우리를 위해 정의된 정적 클래스를 사용하여 메모리 공간을 분류합니다.PyModule_Create()
생성 모듈을 사용하십시오 .- 그런 다음
PyModule_AddObject()
우리가 정의한 클래스를 모듈에 등록하는 데 사용합니다.
자세한 과정은 아래 데모를 참고해주세요
2.5 설정 스크립트를 작성하고 C 언어를 so, pyd 및 기타 형식으로 컴파일
# file name 'setup.py'
from distutils.core import setup, Extension
module1 = Extension('moduleName', sources = ['moduleName.c'])
setup (name = 'moduleName'
version = '1.0'
description = 'This is a Demo'
ext_modules = [module1 ])
위 코드의 moduleName을 자신의 모듈 이름으로 바꾸고 해당 C 파일을 소스에 추가합니다. 헤더 파일을 추가할 필요가 없습니다. 다음 명령을 사용하여 컴파일하고 설치합니다.
python setup.py build
python setup.py install
물론 C 언어를 호출하는 Python을 구현하는 라이브러리가 많이 있습니다. 예를 들어
- 사이썬
- cffi
- ctypes
- 통음
3. C언어와 Python의 상호운용성 예시
3.1 C 언어 호출 Python
데모.py 파일
def print_c_point(p)
print(p)
main.c 파일
#define PY_SSIZE_T_CLEAN
#include <Python.h>
PyStatus init_python(const char *program_name, const wchar_t *additional_search_path)
{
assert(program_name);
PyStatus status;
PyConfig config;
PyConfig_InitPythonConfig(&config);
status = PyConfig_SetBytesString(&config, &config.program_name, program_name);
if(PyStatus_Exception(status)){
goto done;
}
status = PyConfig_Read(&config)
if(PyStatus_Exception(status)){
goto done;
}
if(additional_search_path){
config.module_search_paths_set = 1;
status = PyWideStringList_Append(&config.module_search_paths, additional_search_path);
if(PyStatus_Exception(status)){
goto done;
}
}
status = Py_InitializeFromConfig(&config);
done:
PyConfig_Clear(&config);
return status;
}
int main(int argc, char *argv[])
{
init_python(argv[0], NULL);
PyRun_SimpleString("from time import time, ctime\n"
"print('Today is', ctime(time()))\n");
File *fp = fopen("path/to/demo.py", "r");
PyRun_SimpleFile(fp, "path/to/demo.py");
PyObject *pyModule, *pyFunc;
PyObject *pyArgs, *pyValue;
pyModule = PyImport_ImportModule(demo.py);
if(!pyModule){
PyErr_Print();
goto end;
}
pyFunc = PyObject_GetAttrString(pyModule, print_c_point);
if(!pyFunc){
Py_DECREF(pyModule);
PyErr_Print();
goto end;
}
if(PyCallable_Check(pyFunc)){
pyArgs = PyTuple_New(1);
for(int i=0;i < 1;++i){
pyValue = PyLong_FromLong(3);
if(!pyValue){
Py_DECREF(pyArgs);
PyErr_Print();
goto end;
}
PyTuple_SetItem(pyArgs, i, pyValue);
}
pyValue = PyObject_CallObject(pyFunc, pyArgs);
Py_DECREF(pyArgs);
if(pyValue){
printf("The result is %ld.\n". PyLong_AsLong(pyValue));
Py_DECREF(pyValue);
} else {
PyErr_Print();
goto end;
}
}
Py_DECREF(pyFunc);
Py_DECREF(pyModule);
end:
if(Py_FinalizeEx() < 0)
exit(-1);
return 0;
}
3.2 파이썬은 C 언어를 호출한다
main.py 파일
import custom
if '__main__' == __name__:
use_custom("custom module", 1234)
custom.c 파일
typedef struct {
PyObject_HEAD
PyObject *user_name;
unsigned int passwd;
} customObject;
static int
custom_clear(customObject *self)
{
Py_CLEAR(self->user_name);
return 0;
}
static void
custom_dealloc(customObject *self)
{
PyObecjt_GC_UnTrack(self);
custom_clear(self);
Py_TYPE(self)->tp_free((PyObject*) self);
}
static PyObject*
custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
customObject *self;
self = (customObject *)type->tp_alloc(type, 0);
if(self != NULL){
self->user_name = PyUnicode_FromString("");
if(self->user_name == NULL){
Py_DECREF(self);
return NULL;
}
self->passwd = 1234;
}
return (PyObject *) self;
}
static int
custom_init(customObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {
"user_name","passwd",NULL};
PyObject *user_name = NULL, *tmp;
if(!PyArg_ParseTupleAndKeywords(args, kwds, "|UkI", kwlist, &user_name, &self->passwd))
return -1;
if(user_name){
tmp = self->user_name;
Py_INCREF(user_name);
self->user_name = user_name;
Py_DECREF(tmp);
}
return 0;
}
static PyMemberDef
custom_members[] = {
{
"passwd", T_ULONG, offset(customObject, passwd), 0, "user password"},
{
NULL}
};
static PyObject *
custom_getusername(customObject *self, void *closure)
{
Py_INCREF(self->user_name);
return self->user_name;
}
static PyObject *
custom_setusername(customObject *self, PyObject *value, void *closure)
{
if(value == NULL) {
PyErr_SetString(PyExc_TypeError, "user name is not NULL");
return -1;
}
if(!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError, "user name should string");
return -1;
}
Py_INCREF(value);
Py_CLEAR(self->user_name);
self->user_name = value;
return 0;
}
static int
custom_getpassword(customObject *self, void *closure)
{
PyObject *tmp = PyLong_FromUnsignedLong(self->passwd);
Py_INCREF(tmp);
return tmp;
}
static int
custom_setpassword(customObject *self, PyObject *value, void *closure)
{
if(value == NULL) {
PyErr_SetString(PyExc_TypeError, "user password is not NULL");
return -1;
}
if(!PyLong_Check(value)) {
PyErr_SetString(PyExc_TypeError, "user password should integer");
return -1;
}
self->passwd = PyLong_AsUnsignedLong(value);
return 0;
}
static PyGetSetDef
custom_getsetters[] = {
{
"user_name", (getter)custom_getusername, (setter)custom_setusername, "user name", NULL},
{
"passwd", (getter)custom_getpassword, (setter)custom_setpassword, "user password", NULL},
{
NULL}
};
static PyObject*
custom_printUserInfo(customObject *self, PyObject *Py_UNUSED(ignored))
{
printf("user name is %s and password is %ld.\n",self->user_name,self->passwd);
}
static PyMethodDef custom_methods[] = {
{
"custom_printUserInfo", (PyCFunction) custom_printUserInfo, METH_NOARGS, "print user info"},
{
NULL}
};
static PyTypeObject customType = {
PyVarObject_HEAD_INIT(NULL,0)
.tp_name = "custom.custom",
.tp_doc = PyDoc_STR("custom object"),
.tp_basicsize = sizeof(customObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.tp_new = custom_new,
.tp_init = (initproc)custom_init,
.tp_dealloc = (destructor) custom_dealloc,
.tp_clear = (inquiry) custom_clear,
.tp_members = custom_members,
.tp_methods = custom_methods,
.tp_getset = custom_getsetters,
};
static PyModuleDef custommodule = {
PyModuleDef_HEAD_INIT,
.m_name = "custom",
.m_doc = "example module that creates an extension type",
.m_size = 1
};
PyMODINIT_FUNC
PyInit_custom(void)
{
PyObject *m;
if(PyType_Ready(&customType) < 0)
return NULL;
m = PyModule_Create(&custommodule);
if(m == NULL) return NULL;
Py_INCREF(&customType);
if(PyModule_AddObject(m, "custom", (PyObject*)&customType) < 0){
Py_DECREF(&customType);
Py_DECREF(m);
return NULL;
}
return m;
}