Python 和 ctypes:将 Struct 作为引用传递并在 python 中获取“空指针访问”?

问题描述 投票:0回答:1

我有一个 DLL,它分配内存,向结构中添加数据。并将数据返回给python代码。但是,在 Python 代码中获得了“空指针访问”。

C 文件:(getatt.c) --- 构建后生成 getatt.dll 文件。

typedef struct _ATTO {
    char title[132 + 1];
    char val[132 + 1];
} ATT;

__declspec(dllexport) void get_file_attributes(char* psFileName, ATT** *StructAtt, int* iTotalAtt) {
    int j = 0;
    int iError = NONE;
    char cMessage[132 + 1] = "";
    int iNumAtt = 5;

    StructAtt = (ATT***)malloc(iNumAtt * sizeof(ATT**));
    if(StructAtt == NULL) {
        fprintf(stderr, "Memory allocation failed\n");
        return;
    }
    if(iNumAtt > 0) {
        for(i = 0; i < iNumAtt; i++) {
            StructAtt[i] = malloc(sizeof(ATT*));
            if(StructAtt[i] == NULL) {
                fprintf(stderr, "Memory allocation failed\n");
                return ;
            }

            for(j = 0; j < 1; j++) {
                StructAtt[i][j] = (ATT*)malloc(sizeof(ATT));
                if(StructAtt[i][j] == NULL) {
                    fprintf(stderr, "Memory allocation failed\n");
                    return ;
                }

                strcpy((StructAtt[i][j])->title, psStructAttInfoTitle[i]); //psStructAttInfoTitle is an array of titles
                strcpy((StructAtt[i][j])->val, psStructAttInfoVal[i]);   //psStructAttInfoVal is an array of values
                sprintf(cMessage, "%s=%s\n", StructAtt[i][j]->title, StructAtt[i][j]->val);
                //  write_output(cMessage);
            }
        }
    }

    // Display values
    for(i = 0; i < iNumAtt; i++) {
        for(j = 0; j < 1; j++) {
            sprintf(message, "%s=%s\n", (StructAtt)[i][j]->title, (StructAtt)[i][j]->val);
            write_output(message);
        }
    }

    *iTotalAtt = iNumAtt;
    return;
}

结果:

TYPE=0
SUF=C
GROUP=a
OWNER=unknown
NUMSUF=467

另外,我有一个访问此函数的Python代码:

import ctypes
from ctypes import *

class PY_STRUCT(Structure):
    _fields_ = [('title', c_char * 133),
                ('value', c_char * 133)]

file_name = 'Forest23wd'
file_att_dll = CDLL('./getatt')
file_attribute_dll.get_file_attributes.argtypes = [c_char_p, POINTER(POINTER(POINTER(PY_STRUCT))),POINTER(c_int)]

file_name_str = c_char_p(file_name.encode('utf-8'))
attr_list = POINTER(POINTER(PY_STRUCT))()
total_attr = c_int(0)

file_att_dll.get_file_attributes(file_name_str, byref(attr_list), byref(total_attr))

# Accessing data
print(total_attr.value)
print(attr_list[0][0].contents.title) # ValueError: NULL pointer access...

我得到的total_attr是5。这看起来不错。 我期待

attr_list[0][0]
会是“TYPE”。但我收到错误
ValueError: NULL pointer access.
知道我哪里做错了吗?有什么建议请留言。

python ctypes
1个回答
0
投票

您需要多一层间接。

在C代码中,需要返回

StructAtt
(一个ATT***),所以函数应该是:

__declspec(dllexport) void get_file_attributes(char* psFileName, ATT*** *pStructAtt, int* iTotalAtt) {

    ATT*** StructAtt = malloc(iNumAtt * sizeof(ATT**)); // don't cast malloc in C
...
    *iTotalAtt = iNumAtt;
    *pStructAtt = &StructAtt;
}

然后,在 Python 中,更新

.argtypes
attr_list

file_attribute_dll.get_file_attributes.argtypes = [c_char_p, POINTER(POINTER(POINTER(POINTER(PY_STRUCT))),POINTER(c_int)]
...
attr_list = POINTER(POINTER(POINTER(PY_STRUCT)))()
© www.soinside.com 2019 - 2024. All rights reserved.