美文网首页
记一次坑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