linux下python3调用c代码或者python3调用c++代码

时间:2022-04-27 02:36:17

前几篇的blog都是为了这个实验做基础,先说

原因是python调用数据库150w条数据22s,然后处理数据,其实就2个简单的for循环,65s

需求:

  1. python调用c++函数

  2. c++调用mysql,查询数据,逻辑处理(暂时不用,稍微复杂)直接打印就好,然后返回给python

  3. python收到处理后的数据,打印

实验结果:

  c++调用mysql报错mysql.h error到现在也没解决,只能改成c用

  结果就是3s处理完了,简直完爆,牛的可怕

涉及知识:

  debian系列下c++调用mysql, linux下面安装mysql.h文件

  linux c调用 mysql代码

  

1. python调用简单c或c++代码样例

例子1:

例子1我没测试。

#include<iostream>
using namespace std;
void foo2(int a,int b)
{
cout<<a<<" "<<b<<endl;
}
//编译C++,一定要加extern "C",注意C为大写,小写会无法识别
extern "C"
{
void cfoo2(int a,int b)
{
foo2(a,b);
}
}

test1.cpp

g++ -o test1.so -shared -fPIC test1.cpp

-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件;
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll("./test1.so")
lib.cfoo2(, )

例子2:

已测试

c++代码

extern "C"

{

  int sum(){
return ;
}
}

标准代码:

#ifdef __cplusplus
extern "C"
{
int sum(){
return ;
}
}
#endif

为什么?

这样的代码到底是什么意思呢?首先,__cplusplus是cpp中的自定义宏,那么定义了这个宏的话表示这是一段cpp的代码,也就是说,上面的代码的含义是:如果这是一段cpp的代码,那么加入extern "C"{和}处理其中的代码。

  要明白为何使用extern "C",还得从cpp中对函数的重载处理开始说起。在c++中,为了支持重载机制,在编译生成的汇编码中,要对函数的名字进行一些处理,加入比如函数的返回类型等等.而在C中,只是简单的函数名字而已,不会加入其他的信息.也就是说:C++和C对产生的函数名字的处理是不一样的.

当然我的超级c++版本

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql/mysql.h>
#include <time.h> #include <iostream>
#include <string>
#include <set> using namespace std; MYSQL *g_conn; // mysql 连接
MYSQL_RES *g_res; // mysql 记录集
MYSQL_ROW g_row; // 字符串数组,mysql 记录行 #define MAX_BUF_SIZE 1024 // 缓冲区最大字节数 const char *g_host_name = "localhost";
const char *g_user_name = "root";
const char *g_password = "python123";
const char *g_db_name = "db_data_20170524164100";
const unsigned int g_db_port = ; void print_mysql_error(const char *msg) // 打印最后一次错误
{
if (msg)
printf("%s: %s\n", msg, mysql_error(g_conn));
else
puts(mysql_error(g_conn));
} int executesql(const char * sql)
{
/*query the database according the sql*/
if (mysql_real_query(g_conn, sql, strlen(sql))) // 如果失败
return -; // 表示失败 return ; // 成功执行
} int init_mysql() // 初始化连接
{
// init the database connection
g_conn = mysql_init(NULL); /* connect the database */
if(!mysql_real_connect(g_conn, g_host_name, g_user_name, g_password, g_db_name, g_db_port, NULL, )) // 如果失败
return -; // 是否连接已经可用
executesql("set names utf8"); // 如果失败
// return -1;
return ; // 返回成功
}
extern "C" {
int mysqlPP()
{
if (init_mysql());
print_mysql_error(NULL); char sql[MAX_BUF_SIZE]; int firstTime = time((time_t*)NULL);
printf("firstTime is: %d\n", firstTime); if (executesql("select * from data_stats_gov_cn_diqu_niandu")) // 句末没有分号
print_mysql_error(NULL); g_res = mysql_store_result(g_conn); // 从服务器传送结果集至本地,mysql_use_result直接使用服务器上的记录集 int iNum_rows = mysql_num_rows(g_res); // 得到记录的行数
int iNum_fields = mysql_num_fields(g_res); // 得到记录的列数 printf("共%d个记录,每个记录%d字段\n", iNum_rows, iNum_fields);
set<string> myset;
set<string>::iterator it; while ((g_row=mysql_fetch_row(g_res))) // 打印结果集 myset.insert(g_row[]); // spacename int secodnTime = time((time_t*)NULL);
printf("secodnTime is: %d\n", secodnTime); for (it=myset.begin(); it!=myset.end(); ++it)
std::cout << ' ' << *it << '\n'; int remainTime = secodnTime - firstTime;
printf("remainTime is: %d\n", remainTime); mysql_free_result(g_res); // 释放结果集 mysql_close(g_conn); // 关闭链接 return EXIT_SUCCESS;
}
}

编译c++的命令

g++ -g -o mysql.so -I /usr/include/mysql main.cpp -L /usr/lib/x86_64-linux-gnu/ -lmysqlclient -lz -lpthread -shared -fPIC

编译的时候要注意用到2个路径,mysql.h和libmysqlclient.so的路径

查找mysql.h路径

[root@liu mysql]# find / -name 'mysql.h'
/usr/include/mysql/mysql.h
[root@liu mysql]# find / -name '*mysqlclient*'
/usr/lib/x86_64-linux-gnu/libmysqlclient.so.18.0.
/usr/lib/x86_64-linux-gnu/libmysqlclient_r.so.
/usr/lib/x86_64-linux-gnu/libmysqlclient.a
/usr/lib/x86_64-linux-gnu/libmysqlclient_r.a
/usr/lib/x86_64-linux-gnu/libmysqlclient.so
/usr/lib/x86_64-linux-gnu/libmysqlclient_r.so
/usr/lib/x86_64-linux-gnu/libmysqlclient_r.so.18.0.
/usr/lib/x86_64-linux-gnu/libmysqlclient.so.

python代码

#!/usr/bin/env python
# -*- coding:utf- -*- import time
from ctypes import *
def main():
start_time = time.time()
result = cdll.LoadLibrary("./test.so")
print(result.sum(, )) if __name__ == '__main__':
main()

python3在调用c代码或c++代码时向内传递参数

c++代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql/mysql.h>
#include <time.h> #include <iostream>
#include <string>
#include <set> using namespace std; MYSQL *g_conn; // mysql 连接
MYSQL_RES *g_res; // mysql 记录集
MYSQL_ROW g_row; // 字符串数组,mysql 记录行 #define MAX_BUF_SIZE 1024 // 缓冲区最大字节数
void print_mysql_error(const char *msg) // 打印最后一次错误
{
if (msg)
printf("%s: %s\n", msg, mysql_error(g_conn));
else
puts(mysql_error(g_conn));
} int executesql(const char * sql)
{
/*query the database according the sql*/
if (mysql_real_query(g_conn, sql, strlen(sql))) // 如果失败
return -; // 表示失败 return ; // 成功执行
} int init_mysql(const char *g_host_name ,const char *g_user_name, const char *g_password, const char *g_db_name, const unsigned int g_db_port) // 初始化连接
{ // init the database connection
g_conn = mysql_init(NULL); /* connect the database */
if(!mysql_real_connect(g_conn, g_host_name, g_user_name, g_password, g_db_name, g_db_port, NULL, )) // 如果失败
return -; // 是否连接已经可用
executesql("set names utf8"); // 如果失败
// return -1;
return ; // 返回成功
} extern "C" {
int mysqlPP( char *g_host_name , char *g_user_name, char *g_password, char *g_db_name, unsigned int g_db_port)
{
printf("g_host_name: %s\n", g_host_name);
printf("g_user_name: %s\n", g_user_name);
printf("g_password: %s\n", g_password);
printf("g_db_name: %s\n", g_db_name);
printf("g_db_port: %d\n", g_db_port); if (init_mysql( g_host_name , g_user_name, g_password, g_db_name, g_db_port));
print_mysql_error(NULL); char sql[MAX_BUF_SIZE]; int firstTime = time((time_t*)NULL);
printf("firstTime is: %d\n", firstTime); if (executesql("select * from data_stats_gov_cn_diqu_niandu")) // 句末没有分号
print_mysql_error(NULL); g_res = mysql_store_result(g_conn); // 从服务器传送结果集至本地,mysql_use_result直接使用服务器上的记录集 int iNum_rows = mysql_num_rows(g_res); // 得到记录的行数
int iNum_fields = mysql_num_fields(g_res); // 得到记录的列数 printf("共%d个记录,每个记录%d字段\n", iNum_rows, iNum_fields);
set<string> myset;
set<string>::iterator it; while ((g_row=mysql_fetch_row(g_res))) // 打印结果集 myset.insert(g_row[]); // spacename int secodnTime = time((time_t*)NULL);
printf("secodnTime is: %d\n", secodnTime); for (it=myset.begin(); it!=myset.end(); ++it)
std::cout << ' ' << *it << '\n'; int remainTime = secodnTime - firstTime;
printf("remainTime is: %d\n", remainTime); mysql_free_result(g_res); // 释放结果集 mysql_close(g_conn); // 关闭链接 return ;
}
}

python代码:

#!/usr/bin/env python
# -*- coding:utf- -*- import time
from ctypes import *
def main():
hostname = bytes("127.0.0.1", encoding='utf-8')
username = bytes("root", encoding='utf-8')
password = bytes("python123", encoding='utf-8')
dbname = bytes("db_data_20170524164100", encoding='utf-8')
port =
result = cdll.LoadLibrary("./mysql.so")
result.mysqlPP(hostname, username, password, dbname, port) if __name__ == '__main__':
main()

python3向c, c++传递参数格式转换

#include <stdio.h>
#include <string.h>
struct test
{
int key;
char* val;
}; //传递数值
int ValTest(int n)
{
printf("val:%d\n", n);
return ;
} //传递字符串
int strTest(char* pVal)
{
printf("val:%s\n", pVal);
return ;
} //传递结构体
int StructTest(struct test data)
{
printf("key:%d,val:%s\n", data.key, data.val);
return ;
} //传递结构体指针
int PointTest(struct test* pData)
{
printf("key:%d,val:%s\n", pData->key, pData->val);
return ;
} //传递数组
int szTest(int a[], int nLen)
{
for(int i = ; i < nLen; i++)
{
printf("%d ", a[i]);
}
printf("\n");
return ;
}
# -*- coding: utf8 -*-

import ctypes
from ctypes import * print('*' * )
print("传递数字")
func = ctypes.cdll.LoadLibrary("./pycall.so")
func.ValTest() print('*' * )
print("传递字符串")
val = bytes('qqqqqq',encoding='utf-8')
func.strTest(val) print('*' * )
print("传递结构体")
class testStruct(Structure):
_fields_=[('key',c_int),('val',c_char_p)] s = testStruct()
s.key =
s.val = bytes('test',encoding='utf-8');
func.StructTest(s) print('*' * )
print("传递结构体指针")
func.PointTest(byref(s)) print('*' * )
print("传递数组")
INPUT = c_int *
data = INPUT()
for i in range():
data[i] = i func.szTest(data,len(data))
print ('*' * )

makefile

#COMPLILER USED
CC = gcc
AR = ar cru #SO FLAG
SHARE = -shared -fPIC TARGET = pycall #EXE PGM AND LIB
all: ${TARGET} #MAKE RULE
${TARGET}:
$(CC) $@.c $(SHARE) $^ -o $@.so clean:
rm -f ${TARGET}.so

最后一步,python调用c++,c++返回数组

参考链接:https://blog.csdn.net/uniqsa/article/details/78603082

优化后的代码,但存在问题

问题1:

  代码有缺陷,就是python需要先创建内存地址,可我怎么需要创建多少个地址呢?
  你知道吗?未知呀

问题2:

  对于我来说,c++技术很差,假设我想要字符串类型的怎么处理呢?

  解决方法:

    练啊,笨

问题3:

  如果是c++创建的内存,是不是要由c++注销呢,可注销了python就拿不到了,可不注销内存,python怎么注销这段内存呢?

一、三的解决方法:

  用session的方式呀,缓存呀,笨,是不是傻

技术太渣的忧伤

cpp代码

#include <iostream>

using namespace std;
typedef unsigned char BYTE;
#define MAX_COUNT 20 #if defined(WIN32) || defined(WINDOWS)
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT
#endif struct ByteArrayNew_20_3
{
BYTE e[][];
}; class TestLib
{
public: void LogicFuncNew(ByteArrayNew_20_3 &ret);
}; void TestLib::LogicFuncNew(ByteArrayNew_20_3 &ret)
{
ret.e[][] = ;
ret.e[][] = ;
ret.e[][] = ;
ret.e[][] = ;
ret.e[][] = ;
ret.e[][] = ; cout << "TestLib::LogicFuncNew" << endl;
} extern "C" {
TestLib oGameLogic; void DLL_EXPORT display2(ByteArrayNew_20_3 *pret)
{
cout << "cpp display2 func begin" << endl; oGameLogic.LogicFuncNew(*pret); cout << "cpp display2 func end" << endl;
}
}

py代码

import ctypes

class ByteArray_20(ctypes.Structure):
"""
这里对应着c++代码里的两层数组的第二层 struct ByteArrayNew_20_3 {
BYTE e[3][20];
}; """
_fields_ = [("e1", ctypes.c_ubyte),
("e2", ctypes.c_ubyte),
("e3", ctypes.c_ubyte),
("e4", ctypes.c_ubyte),
("e5", ctypes.c_ubyte),
("e6", ctypes.c_ubyte),
("e7", ctypes.c_ubyte),
("e8", ctypes.c_ubyte),
("e9", ctypes.c_ubyte),
("e10", ctypes.c_ubyte),
("e11", ctypes.c_ubyte),
("e12", ctypes.c_ubyte),
("e13", ctypes.c_ubyte),
("e14", ctypes.c_ubyte),
("e15", ctypes.c_ubyte),
("e16", ctypes.c_ubyte),
("e17", ctypes.c_ubyte),
("e18", ctypes.c_ubyte),
("e19", ctypes.c_ubyte),
("e20", ctypes.c_ubyte)] class ByteArray_20_3(ctypes.Structure):
"""
这里对应着第一层 的 3
struct ByteArrayNew_20_3 {
BYTE e[3][20];
}; """
_fields_ = [
("e1", ByteArray_20),
("e2", ByteArray_20),
("e3", ByteArray_20)] so = ctypes.cdll.LoadLibrary
lib = so("/opt/code/my_code/test_zip/test2/mysql.so") # 代码有缺陷,就是python需要先创建内存地址,可我怎么需要创建多少个地址呢?
# 你知道吗?未知呀 ret = ByteArray_20_3() lib.display2(ctypes.byref(ret)) print(ret.e1.e1)
print(ret.e1.e2)
print(ret.e1.e3)
print(ret.e2.e1)
print(ret.e2.e2)
print(ret.e2.e3)

linux下python3调用c代码或者python3调用c++代码的更多相关文章

  1. Linux下gcc编译生成动态链接库&ast;&period;so文件并调用它【转载】

    动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一 ...

  2. Linux下gcc编译生成动态链接库&ast;&period;so文件并调用它 是转载的

    动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一 ...

  3. Linux下gcc编译生成动态链接库&ast;&period;so文件并调用它

    动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一 ...

  4. Redis进阶实践之八Lua的Cjson在Linux下安装、使用和用C&num;调用Lua脚本

    一.引言         学习Redis也有一段时间了,感触还是颇多的,但是自己很清楚,路还很长,还要继续.上一篇文章简要的介绍了如何在Linux环境下安装Lua,并介绍了在Linux环境下如何编写L ...

  5. Linux下gcc编译生成动态链接库&ast;&period;so文件并调用它(注:执行Test程序后无需用export 命令指定&period;so库文件路径:方法在文中下方;)

    动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一 ...

  6. c&plus;&plus; 网络编程(一)TCP&sol;UDP windows&sol;linux 下入门级socket通信 客户端与服务端交互代码

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9601511.html c++ 网络编程(一)TCP/UDP  入门级客户端与服务端交互代码 网 ...

  7. LInux下(centos7&period;2)更新 python3&period;7

    进入超级管理员目录  su root 下载 wget https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tgz 找到下载的文件解压  tar - ...

  8. Linux下实现流水灯等功能的LED驱动代码及测试实例

    驱动代码: #include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> ...

  9. (转)Linux下数据段的区别(数据段、代码段、堆栈段、BSS段)

    进程(执行的程序)会占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等.不过进程对这些内存的管理方式因内存用途 不一而不尽相同,有些内存是事先静态分配和统一回收的, ...

  10. Linux下objdump查看C程序编译后的汇编代码

    http://m.blog.csdn.net/article/details?id=47747047 Uboot中start.S源码的指令级的详尽解析 http://www.crifan.com/fi ...

随机推荐

  1. 图形化查看maven的dependency依赖

    开发项目的时候,我们想知道一个maven的依赖库是来自那个工程,eclipse有插件可以直接看Dependency Hierarchy,推荐一个第三方的工具yED 在工程的pom.xml文件中添加如下 ...

  2. C语言文件处理

    数据存储方式: 数据->变量->文件 数据 10个学生的信息: #define N 10 struct student { char stu_num[15]; char stu_name[ ...

  3. VS产生sdf和ipch文件太大处理方案

    方法: 工具-->选项-->文本编辑器-->C/C++-->高级-->回退位置,把始终使用回退位置设置为true,回退位置已在使用,不警告也设置为true,回退位置设置为 ...

  4. ajax 加载不同数据

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  5. C&plus;&plus;11笔记

    __func__宏 __func__返回当前的函数名,也可以返回class和struct名. /*返回函数名hello*/ const char* hello() { return __func__; ...

  6. C&plus;&plus; 空类默认产生成员函数

    class Empty { Empty(){...} //默认构造函数 ~Empty(){...} //默认析构函数 Empty(const Empty&){...} //拷贝构造函数 Emp ...

  7. HDU 1796 Howmany integers can you find &lpar;容斥原理&rpar;

    How many integers can you find Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 65536/32768 ...

  8. Loadrunner学习资料

    辅导书籍(书的价值主要在学习的人,而不在书本身) 于涌 | 精通软件性能测试与LoadRunner实战京东 点击查看 柳胜 | 性能测试从零开始京东 点击查看适合零基础的同学学习 柳胜 | LoadR ...

  9. kali网络配置

    touch 1.txt#创建一个文件 配置网卡 auto eth0iface eth0 inet staticaddress 172.16.30.102#要设置的主机IP地址netmask 255.2 ...

  10. sac cut

    Put a perl script here in order to remind myself of its correct usage: