You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python2转Python3时ctypes调用带char*参数的C函数报错原因排查

Python2到Python3 ctypes迁移:访问冲突错误原因分析

问题场景

将Python2中基于ctypes调用C函数的代码迁移至Python3.11时,触发内存访问错误:
OSError: exception: access violation writing 0x00000000000094E0

C代码(mydll.c)

// mydll.c
#include <stdio.h>

void myfunc(char* c, int i, char* c2) {
    printf("Hello World");
}

int main() {
    return 0;
}

Python代码(foo.py)

# foo.py
import ctypes
import sys

PY3 = sys.version_info.major == 3

if PY3:
    clibrary = ctypes.WinDLL("mydll.dll", winmode=1)
else:
    clibrary = ctypes.WinDLL("mydll.dll")

prototype = ctypes.CFUNCTYPE(None, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p)

c1 = (ctypes.c_char * 512)()
i = ctypes.c_int(0)
c2 = (ctypes.c_char * (600 * 8))()
func = prototype(("myfunc", clibrary))

func(c1, i, c2)

错误根源

问题核心是调用约定不匹配,和字符串编码无关:

  • ctypes.WinDLL默认加载的函数使用stdcall调用约定,但CFUNCTYPE默认采用cdecl调用约定。Python2中ctypes实现较宽松,未触发明显错误;Python3的ctypes对调用栈校验更严格,两种约定混用导致栈结构损坏,最终引发内存访问冲突。
  • 若你的C函数用MSVC编译,默认是cdecl约定(除非显式声明__stdcall),此时用WinDLL加载库本身就和函数约定不匹配,再叠加CFUNCTYPE的约定差异,直接触发错误。

修复方案

两种方式二选一,确保调用约定完全匹配:

方案1:使用对应WinDLL的原型类型

WinDLL加载的函数需用WINFUNCTYPE(默认绑定stdcall)定义原型,替换原有的CFUNCTYPE:

prototype = ctypes.WINFUNCTYPE(None, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p)

方案2:改用CDLL加载库(匹配cdecl约定)

若C函数是默认的cdecl约定,改用CDLL加载库,保持CFUNCTYPE原型不变:

# 修改库加载逻辑
if PY3:
    clibrary = ctypes.CDLL("mydll.dll", winmode=1)
else:
    clibrary = ctypes.CDLL("mydll.dll")

额外优化:整数参数无需手动封装为ctypes.c_int,直接传数值0即可,ctypes会自动完成类型转换:

func(c1, 0, c2)

验证效果

修改后,Python2和Python3环境下均可正常调用C函数,不会再出现内存访问冲突错误。

内容的提问来源于stack exchange,提问作者ptatulea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 19:05:18