如何将数组和结构传递给需要 3 个 u32 指针作为参数的 c 函数(ctypes)

How to pass arrays and struct to c function that wants 3 u32 pointers as arguments (ctypes)

我必须使用 python 包装一个 c 库。

经过多次尝试,我在这里向您寻求帮助。我没有 c-library 代码,只有 header,所以我可以 post 只有 python 代码和我使用的两个函数的声明。

来自header:

//the function that should map the variables
u32 TDO_data_transfer(u32* tdo_arr, u32* tdo_arr_ind, u32* data_struct)
//a function that modifies the arrays and the struct
u32 IR_DR_all_DUTs()

来自我的 Python 脚本:

from ctypes import *

#Simplify wrapping ctypes functions
def wrap_function(lib, funcname, restype, argtypes):
    func = lib.__getattr__(funcname)
    func.restype = restype
    func.argtypes = argtypes
    return func

filename = "libIBISGen3.so"
libc = CDLL(filename)

tdo=c_uint32()
tdo_ind=c_uint32()    
tdo_arr = pointer(tdo)
tdo_arr_ind = pointer(tdo_ind)

class cerberus_parameter_s(Structure):
    _fields_ = [
        ('opCode', c_uint8),
        ('bitCount', c_uint16),
        ('data', c_uint32*32),
        ('tmsAddress', c_uint8),
        ('readTDO', c_bool),        
        ('isIR', c_bool),
        ('dataTDI', c_uint32*32)
     ]

#create cerberus struct
dt= (c_uint32 * 32)(0)
dtTDI= (c_uint32 * 32)(0)
cerberus= cerberus_parameter_s(0,0,dt,0,0,0,dtTDI)

TDO_data_transfer = wrap_function(libc, 'TDO_data_transfer', c_uint32, [POINTER(c_uint32), POINTER(c_uint32), POINTER(cerberus_parameter_s)])
print(cerberus.readTDO)
print("TDO_data_transfer() returns: ", TDO_data_transfer(tdo_arr, tdo_arr_ind, byref(cerberus)))
print(cerberus.readTDO)
print(cerberus.data[0])
print(tdo_arr[5])

irDrAllDuts = wrap_function(libc, 'IR_DR_all_DUTs', c_uint32,[])
print("IR_DR_all_DUTs() returns: ", irDrAllDuts())
print(cerberus.readTDO)
print(cerberus.data[0])
print(tdo_arr[5])

输出:

TDO_data_transfer() returns:  0
False
0
0
IR_DR_all_DUTs() returns:  50
False
0
0

最后 3 个值应该不同。我知道:我已经更改了脚本中的第三个参数类型以传递结构,但我不知道如何以其他方式进行。这是第一个问题。至少我应该在调用 IR_DR_all_DUTs() 后看到 tdo_arr 和 tdo_arr_ind 的变化,但没有任何反应。

按照建议,我 post 还使用了我同事制作的部分 c# 代码。他做了一个包装纸,然后是脚本。只要struct没有在内存中分配好,他手动分配每个参数以使脚本运行,但理论上,使用ctypes这应该不是问题。

C# 包装器:

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace IBISGen3CBFramework
{
  public static class libIBIS_Gen3
  {
    ...
    public static unsafe class JTagParameter
    {
        public static byte* OpCode;
        public static ushort* BitCount;
        public static uint* DataTms;
        public static byte* TmsAddress;
        public static byte* ReadTdo;
        public static byte* IsIr;
        public static uint* DataTdi;

        public static int GetDataMaxLength()
        {
            return (int)(((uint)TmsAddress - (uint)DataTms) >> 2);
        }
        public static void Init(uint* structStartAddress)
        {
            uint nAddr = (uint)structStartAddress;
            OpCode = (byte*)nAddr;
            BitCount = (ushort*)(nAddr + 2);
            DataTms = (uint*)(nAddr + 4);
            TmsAddress = (byte*)(nAddr + 0x84);
            ReadTdo = (byte*)(nAddr + 0x85);
            IsIr = (byte*)(nAddr + 0x86);
            DataTdi = (uint*)(nAddr + 0x88);
        }
    }
    ...
    [DllImport("libIBIS_Gen3", EntryPoint = "TDO_data_transfer")]
    private static extern uint TDO_data_transfer(ref IntPtr resultPtr, ref IntPtr lengthPtr, ref IntPtr structPtr);
    public static unsafe void GetResultPointer(out uint* resultArr, out uint* lengthArr, out uint maxLength)  
    {
        IntPtr ptr = new IntPtr();
        IntPtr ptr2 = new IntPtr();
        IntPtr ptr3 = new IntPtr();
        maxLength = TDO_data_transfer(ref ptr, ref ptr2, ref ptr3);
        resultArr = (uint*)ptr.ToPointer();
        lengthArr = (uint*)ptr2.ToPointer();
        JTagParameter.Init((uint*)ptr3.ToPointer());
    }
  }
}

请问有没有人可以帮助我?

PS: 请随时纠正我的英语以使问题更清楚。

以下应该有效(当然没有测试):

from ctypes import *

#Simplify wrapping ctypes functions
def wrap_function(lib, funcname, restype, argtypes):
    func = lib.__getattr__(funcname)
    func.restype = restype
    func.argtypes = argtypes
    return func

filename = "libIBISGen3.so"
libc = CDLL(filename)

class cerberus_parameter_s(Structure):
    _fields_ = [
        ('opCode', c_uint8),
        ('bitCount', c_uint16),
        ('data', c_uint32*32),
        ('tmsAddress', c_uint8),
        ('readTDO', c_bool),        
        ('isIR', c_bool),
        ('dataTDI', c_uint32*32)
     ]

tdo_arr = POINTER(c_uint32)()
tdo_arr_ind = POINTER(c_uint32)()
cerberus_p = POINTER(cerberus_parameter_s)()

TDO_data_transfer = wrap_function(libc, 'TDO_data_transfer', c_uint32, [POINTER(POINTER(c_uint32)), POINTER(POINTER(c_uint32)), POINTER(POINTER(cerberus_parameter_s))])
print("TDO_data_transfer() returns: ", TDO_data_transfer(byref(tdo_arr), byref(tdo_arr_ind), byref(cerberus_p)))

cerberus = cerberus_p.contents
print(cerberus.readTDO)
print(cerberus.data[0])
print(tdo_arr[5])

irDrAllDuts = wrap_function(libc, 'IR_DR_all_DUTs', c_uint32,[])
print("IR_DR_all_DUTs() returns: ", irDrAllDuts())
print(cerberus.readTDO)
print(cerberus.data[0])
print(tdo_arr[5])