欢迎访问我的网站,希望内容对您有用,感兴趣的可以加入免费知识星球。

Python中如何调用C动态库?

Python基础 迷途小书童 4年前 (2019-12-08) 3736次浏览 0个评论

软硬件环境

  • ubuntu 18.04 64bit
  • windows 10 64bit
  • Python 3.5.1
  • GCC 4.9
  • visual studio

前言

最近在做 python3 开发中,碰到了一个问题,需要通过调用 C 的一个动态链接库来获取相应的值。扒了扒网络,动手实践了下,形成此文。

linux版的动态库

写个简单的 C 代码,test.c

#include <stdio.h>
#include <stdlib.h>

char * printStr(const char *p,const char *q)
{
    printf("%s",p);
    printf("%s",q);
    return "djstava";
}

通过以下命令编译成动态链接库

gcc -fPIC -shared -o libtest.so test.c

python3中调用

要调用 C 库中的函数,需要用到 ctypes 这个模块

# -*- coding: utf-8 -*-
__author__ = 'djstava'

from ctypes import *

handle = cdll.LoadLibrary('libtest.so')
func = handle.printStr
func.argtypes = (c_char_p,c_char_p)
func.restype = c_char_p
tmp = handle.printStr("hello".encode("utf-8"),"world".encode("utf-8"))
print(tmp.decode("utf-8"))

程序执行结果

helloworlddjstava

程序解释

func.argtypes = (c_char_p,c_char_p)
func.restype = c_char_p

这2句是分别设置参数数据类型和返回值类型,如果不进行设置,直接调用的话,参数可以正常接收,但是返回值永远是个 int 值,传入的字符串参数必须为 encode("utf-8"),否则在 c 库中仅会打印为首字符

handle = cdll.LoadLibrary('libtest.so')
ret = handle.printStr("hello".encode("utf-8"),"world".encode("utf-8"))

关于其它数据类型的 argtypes 的设置,请查阅参考文献中的链接

windows版的动态库

Visual Studio 编译 dll,在需要抛出的方法前加入 __declspec(dllexport), 比如下面 C 代码

__declspec(dllexport) unsigned int crc32( const unsigned char *s, unsigned int len)
{
  unsigned int i;
  unsigned int crc32val=0xffffffff;
 printf("len==%d\n",len);
  for (i = 0;  i < len;  i ++)
      crc32val =  crc32_tab[(crc32val ^ s[i]) & 0xff] ^ ((crc32val >> 8)&0x00FFFFFF);

  return ~crc32val;
}

然后打开 X64 Native Tools Command Prompt 工具命令行提示符,这里不能使用 powershell 或者 cmd

windows ctype

进入到 C 源码目录,分别执行以下两条命令,第一条命令是生成目标文件 .obj,第二天命令是链接目标文件,生成动态库,生成的 dll 是64位的

cl /c crc.c
link /dll crc.obj

至此,dll 文件就生成了,它就是我们需要的动态链接库, dll 的调用跟 so 的方法一样。

python call c

备注

如果在 python 调用时报如下的错误

  File "client.py", line 35, in <module>
    data_crc = CRC.calcStrCRC(recv_buffer[20:], recv_buffer[8] - 14)
  File "D:\longjing\clientdemo\crc.py", line 33, in calcStrCRC
    handle = cdll.LoadLibrary('crc.dll')
  File "D:\tools\anaconda3\lib\ctypes\__init__.py", line 426, in LoadLibrary
    return self._dlltype(name)
  File "D:\tools\anaconda3\lib\ctypes\__init__.py", line 348, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: [WinError 193] %1 不是有效的 Win32 应用程序。

大概率是 dll 位数不匹配的问题。这里提供一个查看 dll 到底是32位还是64位的方法,即使用 Visual Studio 自带的工具 dumpbin

dumpbin /headers libipanelcrc_64bit.dll

windows ctype

参考资料

喜欢 (0)

您必须 登录 才能发表评论!

Ads Blocker Image Powered by Code Help Pro

Ads Blocker Detected!!!

请关闭 Adblock 等类似浏览器插件,然后刷新页面访问,感谢您的支持!

We have detected that you are using extensions to block ads. Please support us by disabling these ads blocker.