为什么我需要__declspec(dllexport)才能使某些函数可从ctypes访问?

发布于 2021-01-29 16:02:45

因此,我正在学习利用Python ctypes模块。
这是我在Windows上使用gcc -shared(版本4.8)进行编译以获取示例.dll的简单C文件:

#include <stdio.h>
int addition(int a, int b){
    return a+b;
}

我现在可以像这样从Python访问它:

>>>from ctypes import *
>>>mylibc = CDLL(r"somepath\mysample.dll")
>>>mylibc.addition
<_FuncPtr object at 0x00000000031456C8>
>>>mylibc.addition(2,3)
5

现在,我尝试对包含此功能的其他更大,更复杂的.c文件执行相同的操作:

__declspec(dllexport) void __stdcall
flopequity(HW hero[], HW villain[], double hcounters[],
double vcounters[], double hsums[], double vsums[], ulong board,
__int32 lenh, __int32 lenv)

其中HW是结构的typedef。我使用GCC进行编译,并且可以像以前一样访问该函数,但是当我删除__declspec(dllexport)或_
stdcall(或两者)时,该函数将不再可用。
我的问题是,为什么我可以从第一个示例访问简单功能,却无法访问更复杂的功能,这是什么原因?_编译C代码并从ctypes访问它时
,使用调用约定/
_declspec _的规则是什么

关注者
0
被浏览
50
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    gcc 似乎默认情况下会导出功能,您可以使用任何PE查看器(例如PE Explorer)(“查看”>“导出”)查看导出的功能:

    在此处输入图片说明

    但是,如果尝试使用VC ++编译此代码,它将不会为您导出此函数,您会看到没有导出的函数:

    在此处输入图片说明

    您需要要求它导出此功能:

    __declspec(dllexport) int addition(int a, int b){
        return a+b;
    }
    

    至于调用约定,规则很简单:

    如果您的函数使用__stdcall,作为大多数Win32API,则需要使用WinDLL('mylib.dll')或导入DLL
    windll.mylib,例如:

    > type mylib.c
    __declspec(dllexport) int __stdcall addition(int a, int b) {
        return a+b;
    }
    
    ***********************************************************************
    
    > cl mylib.c /link /dll /out:mylib.dll
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
    
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    mylib.c
    Microsoft (R) Incremental Linker Version 8.00.50727.762
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /out:mylib.exe
    /dll
    /out:mylib.dll
    mylib.obj
       Creating library mylib.lib and object mylib.exp
    
    ***********************************************************************
    
    > python
    >>> from ctypes import *
    >>>
    >>> WinDLL('mylib.dll').addition(1, 2)
    3
    >>> windll.mylib.addition(1, 2)
    3
    >>>
    

    如果函数使用__cdecl,witch是默认的调用约定,则需要使用CDLL('mylib.dll')或导入DLL cdll.mylib',例如:

    > type mylib.c
    // `__cdecl` is not needed, since it's the default calling convention
    __declspec(dllexport) int addition(int a, int b){
        return a+b;
    }
    
    ***********************************************************************
    
    > cl mylib.c /link /dll /out:mylib.dll
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
    
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    mylib.c
    Microsoft (R) Incremental Linker Version 8.00.50727.762
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /out:mylib.exe
    /dll
    /out:mylib.dll
    mylib.obj
       Creating library mylib.lib and object mylib.exp
    
    ***********************************************************************
    
    > python
    >>> from ctypes import *
    >>>
    >>> CDLL('mylib.dll').addition(1, 2)
    3
    >>> cdll.mylib.addition(1, 2)
    3
    >>>
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看