linux下python3调用c代码或者python3调用c++代码
前几篇的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文件
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++代码的更多相关文章
- Linux下gcc编译生成动态链接库*.so文件并调用它【转载】
动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一 ...
- Linux下gcc编译生成动态链接库*.so文件并调用它 是转载的
动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一 ...
- Linux下gcc编译生成动态链接库*.so文件并调用它
动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一 ...
- Redis进阶实践之八Lua的Cjson在Linux下安装、使用和用C#调用Lua脚本
一.引言 学习Redis也有一段时间了,感触还是颇多的,但是自己很清楚,路还很长,还要继续.上一篇文章简要的介绍了如何在Linux环境下安装Lua,并介绍了在Linux环境下如何编写L ...
- Linux下gcc编译生成动态链接库*.so文件并调用它(注:执行Test程序后无需用export 命令指定.so库文件路径:方法在文中下方;)
动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一 ...
- c++ 网络编程(一)TCP/UDP windows/linux 下入门级socket通信 客户端与服务端交互代码
原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9601511.html c++ 网络编程(一)TCP/UDP 入门级客户端与服务端交互代码 网 ...
- LInux下(centos7.2)更新 python3.7
进入超级管理员目录 su root 下载 wget https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tgz 找到下载的文件解压 tar - ...
- Linux下实现流水灯等功能的LED驱动代码及测试实例
驱动代码: #include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> ...
- (转)Linux下数据段的区别(数据段、代码段、堆栈段、BSS段)
进程(执行的程序)会占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等.不过进程对这些内存的管理方式因内存用途 不一而不尽相同,有些内存是事先静态分配和统一回收的, ...
- Linux下objdump查看C程序编译后的汇编代码
http://m.blog.csdn.net/article/details?id=47747047 Uboot中start.S源码的指令级的详尽解析 http://www.crifan.com/fi ...
随机推荐
- Java 字符编码 ASCII、Unicode、UTF-8、代码点和代码单元
1 ASCII码 统一规定英语字符与二进制位之间的关系.ASCII码一共规定了128个字符的编码.例如,空格“SPACE”是32(二进制00100000),大写字母A是65(二进制01000001). ...
- Cocos Creator_发布到微信小游戏平台
观看官方教程,地址 传送门: http://docs.cocos.com/creator/manual/zh/publish/publish-wechatgame.html CocosCreator接 ...
- 移动端input中的placeholder属性垂直
今天做项目时发现,在手机端用placeholder时,Android手机可以垂直显示:ISO则不能使placeholder垂直;解决办法: .gcddfadf-con-pay-1 input::-we ...
- 模板-gcd
GCD int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); } EXGCD void ex_gcd(int a, int b, int & ...
- 小甲鱼Python视频课后答案(第一讲)---仅记录学习
1.python是什么语言? Python是一种支持面向对象的解释性高级语言,属于脚本语言的一种. 2.IDLE是什么? IDLE是开发python程序的基本IDE(集成开发环境),具备基本的IDE的 ...
- JAVA自学笔记10
JAVA自学笔记10 1.形式参数与返回值 1)类名作为形式参数(基本类型.引用类型) 作形参必须是类的对象 2)抽象类名作形参 需要该抽象类的子类对象,通过多态实现 3)接口名为形参 需要的是该接口 ...
- ASP.NET WebApi 基于JWT实现Token签名认证
一.前言 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NET WebServi ...
- RestTemplate发送请求并携带header信息 RestTemplate post json格式带header信息
原文地址: http://www.cnblogs.com/hujunzheng/p/6018505.html RestTemplate发送请求并携带header信息 v1.使用restTempl ...
- [Linux] - 利用ping给端口加密,限制访问
Linux中,想对特定的端口加密访问,可以使用iptables的ping方式. 作用 访问被限制的端口,必需先ping发送对应的字节包(字节包大小可自行设置,此为密钥)才能访问成功! 下边是对SSH的 ...
- Python import其他文件夹的文件
一般情况下,import的文件和被import的文件在同一个路径下面,import也比较方便.如果这两个文件不在一个路径下面,import就比较麻烦了,需要在被import的文件路径下面新建一个__i ...