python 利用ctypes调用c/c++库一点例子

python 利用ctypes调用c/c++库一点例子

偶然花了几天时间第一次用ctypes编写相关接口,这个虽然不能直接生成python库,但直接调用c/c++库的(个人不太想区分c/c++,一般情况混合用),感觉ctypes是个好东西,而且使用简单,用过了就会发现是真的喜欢,大致记录下,以免忘记(当然好工具也挺多,比如docker,数据库mysql和搭建服务器的 Nginx +gunicorn + flask等工具,个人有点懒,不太想记录,随缘记录了),本例子只是测试python和c/c++数组等数据交互和调用可行,具体需要求根据各自修改:

1. c/c++代码

简单例子,就两个文件test.cpp,test.h,直接贴上来,不太想改动什么,名字随意;

test.h:

头文件:test.h,通过结构体和python端传递数据,当然python端要对应定义类似的结构(听说名字可以不同),主要用指针操作(个人挺喜欢指针的),共享内存,免去拷贝(除非不得已),这里python直接调用vs编译后的dll库,注意python中调用库的路径要匹配上。

#pragma once

//#define ENCODE_API __attribute__((visibility ("default")))//linux 则声明这个,类似MYDLL_API

#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif

#include <iostream>
#include <vector>

typedef struct asrInOutput_ {

    const char* modelName = "";//model file
    float* inputF[3] = { NULL ,NULL ,NULL };//float:intput1,intput3,intput4
    int* inputI = NULL;//int:input2
    int inputSize[4] = { 0,0,0,0 };

    float* outputF[3] = { NULL,NULL,NULL };
    int outputFSize[3] = { 0,0,0 };
    int outBufNumberMax[3] = { 0,0,0 };//new obj number


} asrInOutput;


#ifdef __cplusplus
extern "C" {
#endif

MYDLL_API int asrProcess(asrInOutput* asr);

MYDLL_API void asrRealeas(asrInOutput* asr);

int newOutputBuf(asrInOutput* asr);

MYDLL_API int testInputOutput(asrInOutput* asr);

MYDLL_API int testPrint();


#ifdef __cplusplus
}
#endif

test.cpp:

要注意的是,因为输出的多个数组大小可能不确定,所以例子以这个为前提条件来设计的,具体大小通过另外一个数字来标记,联合使用,这也是使用指针需要注意的地方,要清楚指针指向空间多大、类型什么。

#include "test.h"

using namespace std;

#define toStr(name)  (#name)//linux


#define F_OR_INT_PRINTT
#ifdef  F_OR_INT_PRINTT
typedef float T_NAME;

#else
typedef int T_NAME;

#endif //  F_OR_INT_PRINTT


//template <class T_NAME>
void printArrayData1(std::vector<T_NAME>& data, char* name)
{

	std::cout << "\n***********" << name << ".size()==" << data.size() << "**********" << std::endl;

	char* spData = (char*)"";
	if (std::is_same<T_NAME, int>::value)
	{
		std::cout << "here int type emerges" << std::endl;
		spData = (char*)"%d ";
	}
	else if (std::is_same<T_NAME, float>::value)
	{
		std::cout << "here float type emerges" << std::endl;
		spData = (char*)"%.2f ";
	}

	for (size_t i = 0; i < data.size(); i++)
	{
		if (20 == i % 21) printf("\n");
		printf(spData, data[i]);
	}
	std::cout << "" << std::endl;
}

void printFloat(float* data, int len)
{

	for (size_t i = 0; i < len; i++)
	{
		if (20 == i % 21) printf("\n");
		printf("%.2f ", data[i]);
	}
	std::cout << "\n...................." << std::endl;
}



int antoIncreaseF(std::vector<float>& src, float* dst, float step = 0.01)
{
	for (size_t i = 0; i < src.size(); i++)
	{
		dst[i] = src[i] + step;
	}

	return 0;
}


int asrProcess(asrInOutput* asr)
{

	for (size_t i = 0; i < 3; i++)
	{
		if (NULL == asr->inputF[i])
		{
			cout << "error: some input parameters of intput1,intput3,intput4 is null !!!" << endl;
			return -1;
		}
	}
	if (NULL == asr->inputI)
	{
		cout << "error: some input parameters,input2 is null !!!" << endl;
		return -2;
	}

	printf("model data is %s \n", asr->modelName);

	std::vector<float> input0(asr->inputF[0], asr->inputF[0] + asr->inputSize[0]);
	std::vector<int> input1(asr->inputI, asr->inputI + asr->inputSize[1]);
	std::vector<float> input2(asr->inputF[1], asr->inputF[1] + asr->inputSize[2]);
	std::vector<float> input3(asr->inputF[2], asr->inputF[2] + asr->inputSize[3]);



	//for (size_t i = 0; i < 4; i++)
	//{
	//	std::cout << "sizePtr[" << i << "]==" << asr->inputSize[i] << std::endl;
	//}
	//printf("%s.size==%d \n", toStr(input0), input0.size());
	//printf("%s.size==%d \n", toStr(input1), input1.size());
	//printf("%s.size==%d \n", toStr(input2), input2.size());
	//printf("%s.size==%d \n", toStr(input3), input3.size());

#ifdef  F_OR_INT_PRINTT
	printArrayData1(input0, (char*)toStr(input0));
	printArrayData1(input2, (char*)toStr(input2));
	printArrayData1(input3, (char*)toStr(input3));
#else
	printArrayData1(input1, (char*)toStr(input1));
#endif

	//set outsize buf
	asr->outputFSize[0] = input0.size();
	asr->outputFSize[1] = input2.size();
	asr->outputFSize[2] = input3.size();
	newOutputBuf(asr);



	for (size_t i = 0; i < 3; i++)
	{
		std::cout << "asr->outputF[" << i << "]==" << asr->outputFSize[i] << std::endl;
	}
	

	antoIncreaseF(input0, asr->outputF[0],0.01);
	antoIncreaseF(input2, asr->outputF[1],0.02);
	antoIncreaseF(input3, asr->outputF[2],0.03);






	return  0;
}

int newOutputBuf(asrInOutput* asr)
{
	for (size_t i = 0; i < 3; i++)
	{
		if (asr->outputFSize[i] > asr->outBufNumberMax[i])
		{
			if (NULL != asr->outputF[i])
			{
				printf("delete[] asr->outputF[%d]\n", i);
				delete[] asr->outputF[i];
			}
			asr->outBufNumberMax[i] = asr->outputFSize[i];
			asr->outputF[i] = new float[asr->outBufNumberMax[i]];
			printf("asr->outputF[%d]= new float[asr->outBufNumberMax[%d]\n", i,i);
		}
	}
	return 0;
}

void asrRealeas(asrInOutput* asr)
{
	for (size_t i = 0; i < 3; i++)
	{
		if (NULL != asr->outputF[i])
		{
			delete[] asr->outputF[i];
			asr->outputF[i] = NULL;
		}
	}
}



int testInputOutput(asrInOutput* asr)
{

	int outFSize[3] = { 5,6,8 };

	//pptr[0] = asr->output1;
	//pptr[1] = asr->output2;
	//pptr[2] = asr->output3;

	for (size_t i = 0; i < 3; i++)
	{
		asr->outputFSize[i] = outFSize[i];
		//outputi buf
		if (outFSize[i] > asr->outBufNumberMax[i])
		{
			if (NULL != asr->outputF[i])
			{
				
				printf(" pptr[%d]!=null \n", i);
				delete[] asr->outputF[i];
			}
			else
			{
				printf(" pptr[%d]==null \n",i);
			}
			asr->outBufNumberMax[i] = outFSize[i];
			asr->outputF[i] = new float[asr->outBufNumberMax[i]];
		}
	}


	float ct=1.1;
	for (size_t i = 0; i < 3; i++)
	{
		//std::cout << "line==" << __LINE__ <<"outFSize[i]="<< outFSize[i] << std::endl;
		for (size_t j = 0; j < outFSize[i]; j++)
		{
			ct += 0.1;
			asr->outputF[i][j] = ct;

		}
		printf("asr.outBufNumberMax[%d]==%d\n", i, asr->outBufNumberMax[i]);
		//std::cout << "line==" <<__LINE__<< std::endl;
	}
	std::cout << "testInputOutput end" << std::endl;

	return 0;
}

int testPrint()
{
	std::cout << "c++ can be call,<*>||<*>" <<std::endl;
	return 0;
}

2. python端调用代码

python是直接调用本地vs工程生成的dll库的,如果是linux上,要修改对应头文件和导出声明方式,生成对应so才可被调用,具体可自行查找,个人只是记录一个使用例子,在vs上方便调试所以才有这个例子的。python要特别注意数据类型,比如np.float32才对应c/c++端float,np.int32对应c/c++端int,如果使用默认类型可能不对。至于返回的ctype类型怎么变为numpy类型,则自行探索,最差的可以一个个的赋值。

import platform

import numpy as np
import ctypes
from ctypes import *


class AsrStruct(Structure):
    _fields_ = [('modelName', c_char_p),
                ('inputF', (POINTER(c_float))*3),
                ('inputI', POINTER(c_int)),
                ('inputSize', (c_int * 4)),
                ('outputF', (POINTER(c_float))*3),
                ('outputFSize', (c_int*3)),
                ('outBufNumberMax', (c_int*3)),

                ]

def test2():
    para = AsrStruct()
    lib = CDLL(
        '库路径/ConsoleApplication1/x64/Release/ConsoleApplication1.dll')  # class level loading lib

    # prepare input data
    model_path = 'stream.mnn'.encode("utf-8")

    input_sizes = np.zeros(5, dtype=np.int32)
    input0 = np.arange(1, 5, 0.1, dtype=np.float32)  #
    input_sizes[0] = input0.size

    input1 = np.arange(100, 120, 1, dtype=np.int32)  #
    input_sizes[1] = input1.size

    input2 = np.arange(5, 15, 0.2, dtype=np.float32)  #
    input_sizes[2] = input2.size

    input3 = np.arange(15, 30, 0.3, dtype=np.float32)  #
    input_sizes[3] = input3.size

    para.modelName=c_char_p(model_path)
    para.inputF[0] = input0.ctypes.data_as(POINTER(c_float))
    para.inputI = input1.ctypes.data_as(POINTER(c_int))
    para.inputF[1] = input2.ctypes.data_as(POINTER(c_float))
    para.inputF[2] = input3.ctypes.data_as(POINTER(c_float))

    for i in range(0,4):
        para.inputSize[i]=input_sizes[i]

    outputF=lib.asrProcess(byref(para))

    for i in range(0, 3):
        print('--------------------------------------repeate circle {}-----------------------------------'.format(i))
        for k in range(0,3):
            para.inputF[k]=para.outputF[k]
        para.inputSize[0]=para.outputFSize[0]
        para.inputSize[2]=para.outputFSize[1]
        para.inputSize[3]=para.outputFSize[2]

        outputF = lib.asrProcess(byref(para))

    file_write = open('./1.txt', mode='w')
    for i in range(0,para.outputFSize[0]):
        a=para.outputF[0][i]
        print(a)
        file_write.write("%.5f\n" % a)

    file_write.close()


def test():
    lib = CDLL(
        '库路径/ConsoleApplication1/x64/Release/ConsoleApplication1.dll')  # class level loading lib
    lib.testPrint.restype = c_int
    lib.testPrint()
    para = AsrStruct()

    np1= np.arange(5, 15, 0.2, dtype=np.float32)  #
    para.input1=np1.ctypes.data_as(POINTER(c_float))

    lib.testInputOutput.argtypes=[POINTER(AsrStruct)]
    lib.testInputOutput.restype=c_int
    c=lib.testInputOutput(byref(para))

    print(para.outputFSize[0])
    k1=para.outBufNumberMax

    int_nparray = np.frombuffer(para.outBufNumberMax, dtype=np.int32)
    print(int_nparray)

    file_write = open('./1.txt', mode='w+')
    for i in range(0,para.outputFSize[0]):
        print(para.outputF[0][i])
        file_write.writelines(para.outputF[0][i])

    file_write.close()


    #print(para[0].aa)




if __name__ == '__main__':
    print("hello world")

    print(platform.system())
    #test()
    test2()

备注:

可能例子过于简单,这仅仅做一个记录,但愿对有缘之人有帮助,免得像我一样浪费很多时间去瞎琢磨。一般不回信,时间长了会忘记的,瞄~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值