Python调用C编译DLL的hello函数触发OSError访问违例问题排查
问题:调用DLL中printf函数触发访问违例错误
执行python build.py可正常生成DLL,但运行python main.py时,add_numbers函数可正常工作,调用hello函数却触发错误:“OSError: exception: access violation writing 0x0000000000002C44”。请问遗漏了什么?是否需要特殊处理stdio.h头文件?
相关代码
C代码(my_module.c)
// my_module.c #include <stdio.h> __declspec(dllexport) void hello() { printf("Hello World!\n"); } __declspec(dllexport) int add_numbers(int a, int b) { return a + b; } // entry point int main() { return 0; }
构建脚本(build.py)
# build.py from setuptools._distutils.ccompiler import new_compiler compiler = new_compiler() compiler.compile(["my_module.c"]) compiler.link_shared_lib(["my_module.obj"], "my_module")
主脚本(main.py)
# main.py import ctypes my_module = ctypes.CDLL("./my_module.dll") my_module.add_numbers.argtypes = ctypes.c_int, ctypes.c_int my_module.add_numbers.restype = ctypes.c_int my_module.hello.argtypes = () my_module.hello.restype = None result = my_module.add_numbers(3, 4) print(type(result), result) my_module.hello()
问题原因
核心问题是DLL未正确初始化C标准库的I/O环境:
add_numbers是纯数值计算函数,不依赖C标准库的任何初始化资源,因此可以正常运行。printf属于C标准库函数,需要依赖stdio缓冲区、文件描述符等已初始化的资源才能工作。默认编译配置下,DLL没有触发C标准库的初始化流程,导致printf执行时访问未初始化的内存,触发访问违例。
解决方案
方法1:修改构建脚本,显式配置编译参数
修改build.py,添加编译参数指定使用动态C运行时库,并指定DLL入口点,确保标准库初始化:
# build.py from setuptools._distutils.ccompiler import new_compiler compiler = new_compiler() # 使用动态链接的C运行时库,确保标准库资源能被正确初始化 compiler.compile(["my_module.c"], extra_preargs=["/MD"]) # 指定DLL入口点为DllMainCRTStartup,触发标准库初始化逻辑 compiler.link_shared_lib( ["my_module.obj"], "my_module", extra_link_args=["/ENTRY:DllMainCRTStartup"] )
方法2:在C代码中添加DllMain入口函数
在my_module.c中添加DLL的入口函数DllMain,让系统加载DLL时自动完成C标准库的初始化:
// my_module.c #include <stdio.h> #include <windows.h> // DLL入口函数,系统加载DLL时会调用此函数 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch(fdwReason) { case DLL_PROCESS_ATTACH: // 进程加载DLL时,C标准库会自动完成初始化 break; case DLL_PROCESS_DETACH: // 进程卸载DLL时,自动清理标准库资源 break; } return TRUE; } __declspec(dllexport) void hello() { printf("Hello World!\n"); } __declspec(dllexport) int add_numbers(int a, int b) { return a + b; } int main() { return 0; }
修改后原构建脚本可直接使用,或搭配方法1的/MD参数效果更稳定。
内容的提问来源于stack exchange,提问作者Carlos
相关产品推荐
相关产品推荐

