美文网首页
记一次坑X的Python调用C的.so过程

记一次坑X的Python调用C的.so过程

作者: qboy0000 | 来源:发表于2018-12-02 22:15 被阅读0次

    根据项目需要,我们的一个项目需要使用某司发布的so接口,而我们的项目是用Python编写运行在Linux(64位)平台,所以直接采用ctypes
    根据提供的开发手册结构写定义如下:

    typedef struct
    {
        unsigned short  m_Read_Priv; 
        unsigned short  m_Write_Priv; 
    } DATA_LIC;
    
    typedef struct
    {
        unsigned long    m_Size;
        DATA_LIC         m_Lic;
    } DATA_FILE_ATTR;
    

    根据C语言python结构体如下

    class DATA_LIC(ctypes.Structure):
        _fields_=[
            ("m_Read_Priv",c_ushort),
            ("m_Write_Priv",c_ushort)
        ]
    
    class DATA_FILE_ATTR(ctypes.Structure):
        _fields_=[
            ("m_Size",c_ulong),
            ("m_Lic",DATA_LIC),
        ]
    

    以上代码我看了不下10篇,也没觉得有问题,(如果开发手册是正确的话,也会是没问题的),python结构定义并赋值传给C代码

    data_lic = DATA_LIC()
    data_lic.m_Read_Priv = c_ushort(1)
    data_lic.m_Write_Priv = c_ushort(2)
    data_file_attr = DATA_FILE_ATTR()
    data_file_attr.m_Size = 344
    data_file_attr.m_Lic = data_lic
    # data_file_attr.m_Lic.m_Write_Priv = c_ushort(2)
    

    无论我给m_Read_Priv、m_Write_Priv赋值多少,最终输出的结果都是0,我就纳闷了,我哪传错了,由于第一次用python调用so文件,况且这是结构体套结构体,很容易参数不正确,所以不敢随便说人家是错,总以为是自己哪传的参数不对。
    实在没办法了,我去问对方技术,对方不会python[汗],对方用C写了一个程序运行结果是没有问题的,甚至还发了一个新版本的so文件过来,以为是老版本的问题。
    还是没有找到问题的原因啊,只能我自己继续去找问题啊。后来我实在没有办法了,我就想能不能自己写一个so文件,接口跟他的一致来自己输出结果对比一下

    typedef struct
    {
        unsigned short  m_Read_Priv;
        unsigned short  m_Write_Priv;
    } DATA_LIC;
    
    typedef struct
    {
        unsigned long    m_Size;
        DATA_LIC         m_Lic; 
    } DATA_FILE_ATTR;
    
    extern "C"{//在extern “C”中的函数才能被外部调用
        int  XXX_CreateFile(long hDongle, int nFileType, int wFileID, void * pFileAttr){
            DATA_FILE_ATTR fileAttr = *(DATA_FILE_ATTR*)(pFileAttr);
            cout<<"hDongle:"<<hDongle<<endl;
            cout << "nFileType:"<<nFileType<<endl;
            cout << "wFileID" << wFileID <<endl;
            cout <<"File Attr===>"<<endl;
            cout << "typesize:"<<sizeof(fileAttr)<<endl;
            cout << "m_Size:" << fileAttr.m_Size<<endl;
            cout << "m_Lic.m_Read_Priv:" << fileAttr.m_Lic.m_Read_Priv<<endl;
            cout << "m_Lic.m_Write_Priv:" << fileAttr.m_Lic.m_Write_Priv<<endl;
            return 0;
        }
    }
    

    调用自己写的so文件,所有的参数都是可以正常输出的,并且也是我传入的参数,为此验证,我还特意在DATA_LIC m_Lic的前后另外再加一些参数,也依然没有问题,好吧。在这里我可以断定应该是so可能问题,那么so的问题会出现在哪呢,C语言调用都没有问题,我还特意去运行了一篇对方对供的试例,确实没有问题。
    后来又仔细看了一下对方的C的试例代码并找到了其api.h的结构体定义发现:

    typedef struct
    {
        unsigned int    m_Size;
        DATA_LIC         m_Lic;
    } DATA_FILE_ATTR;
    

    开发手册与api.h文件针对结构体的长度定义不一致,原来问题就出现在。回到自己的python代码,把结构体长度修改成c_uint,运行就正常了。

    C语言中的结构体是聚合数据类型,针对结构体的定义顺序即字段所占字节数有严格意义的规定,而long类型在64位下是用的8字节,而int类型是4字节,可以用sizeof计算,问题就出现在差这4字节中我们定义的长度多占了四字节,因此对方取数据时出错。

    相关文章

      网友评论

          本文标题:记一次坑X的Python调用C的.so过程

          本文链接:https://www.haomeiwen.com/subject/xtvscqtx.html