You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python ctypes调用NI RFSA函数遇空指针错误,需获取结构体数组数据

问题解决:ctypes调用NI RFSA函数获取结构体数组数据

问题背景

调用niRFSA_FetchIQSingleRecordComplexF32时触发空指针错误:

RuntimeError: (-1074134952) IVI: (Hex 0xBFFA0058) Null pointer passed for parameter or attribute.

头文件定义

typedef struct NIComplexNumberF32_struct {
   ViReal32 real;
   ViReal32 imaginary;
} NIComplexNumberF32;

ViStatus _VI_FUNC niRFSA_FetchIQSingleRecordComplexF32(
   ViSession vi,
   ViConstString channelList,
   ViInt64 recordNumber,
   ViInt64 numberOfSamples,
   ViReal64 timeout,
   NIComplexNumberF32* data,
   niRFSA_wfmInfo* wfmInfo);

报错的Python代码

import ctypes

class NIComplexNumberF32_struct_data(ctypes.Structure):
    _fields_ = [("real", ctypes.c_float),
                ("imaginary",  ctypes.c_float)]

class niRFSA_wfmInfo_struct_data(ctypes.Structure):
    _fields_ = [("absoluteInitialX", ctypes.c_double),
                ("relativeInitialX",  ctypes.c_double),
                ("xIncrement",  ctypes.c_double),
                ("actualSamples",  ctypes.c_double),
                ("offset",  ctypes.c_double),
                ("gain",  ctypes.c_double),
                ("reserved1",  ctypes.c_double),
                ("reserved2",  ctypes.c_double)                ]

# 创建空指针,这是错误根源
data = ctypes.POINTER(NIComplexNumberF32_struct_data)()
wfmInfo = ctypes.POINTER(niRFSA_wfmInfo_struct_data)()

dll_path = r"C:\Program Files\IVI Foundation\IVI\bin\NiRFSA_64.dll" 
dll = ctypes.cdll.LoadLibrary(dll_path)
# 注意:这里argtypes里的Vi类型要先定义,比如ViSession是c_longlong或c_void_p,根据实际情况
ViSession = ctypes.c_void_p
ViString = ctypes.c_char_p
ViInt64 = ctypes.c_longlong
ViReal64 = ctypes.c_double

dll.niRFSA_FetchIQSingleRecordComplexF32.argtypes =(ViSession, ViString, ViInt64, ViInt64, ViReal64, 
                                                    ctypes.POINTER(NIComplexNumberF32_struct_data), 
                                                    ctypes.POINTER(niRFSA_wfmInfo_struct_data))
dll.niRFSA_FetchIQSingleRecordComplexF32(handle, b'', 0, 1000, 1, data, wfmInfo)

错误原因

只声明了指针变量,但没有为指针分配实际的内存空间。ctypes.POINTER(...)() 创建的是空指针,函数需要一个指向已分配内存的指针来写入采样数据和波形信息。

解决步骤

  1. 为采样数据数组分配内存:根据传入的numberOfSamples(这里是1000),创建对应数量的结构体实例数组,再通过ctypes.byref或取数组地址的方式传入。
  2. 为波形信息结构体分配内存:创建一个niRFSA_wfmInfo_struct_data实例,传入它的指针供函数填充数据。

修正后的代码

import ctypes

class NIComplexNumberF32_struct_data(ctypes.Structure):
    _fields_ = [("real", ctypes.c_float),
                ("imaginary",  ctypes.c_float)]

class niRFSA_wfmInfo_struct_data(ctypes.Structure):
    _fields_ = [("absoluteInitialX", ctypes.c_double),
                ("relativeInitialX",  ctypes.c_double),
                ("xIncrement",  ctypes.c_double),
                ("actualSamples",  ctypes.c_double),
                ("offset",  ctypes.c_double),
                ("gain",  ctypes.c_double),
                ("reserved1",  ctypes.c_double),
                ("reserved2",  ctypes.c_double)]

# 定义IVI类型(根据NI文档,ViSession通常是c_void_p或c_longlong,这里用c_void_p)
ViSession = ctypes.c_void_p
ViString = ctypes.c_char_p
ViInt64 = ctypes.c_longlong
ViReal64 = ctypes.c_double

# 关键:分配内存
number_of_samples = 1000
# 创建结构体数组,长度为number_of_samples
data_array = (NIComplexNumberF32_struct_data * number_of_samples)()
# 创建波形信息结构体实例
wfm_info = niRFSA_wfmInfo_struct_data()

dll_path = r"C:\Program Files\IVI Foundation\IVI\bin\NiRFSA_64.dll" 
dll = ctypes.cdll.LoadLibrary(dll_path)

# 设置函数参数类型
dll.niRFSA_FetchIQSingleRecordComplexF32.argtypes = (
    ViSession, ViString, ViInt64, ViInt64, ViReal64,
    ctypes.POINTER(NIComplexNumberF32_struct_data),
    ctypes.POINTER(niRFSA_wfmInfo_struct_data)
)
# 设置返回值类型(ViStatus通常是c_long)
dll.niRFSA_FetchIQSingleRecordComplexF32.restype = ctypes.c_long

# 调用函数,传入数组的首地址和wfm_info的指针
status = dll.niRFSA_FetchIQSingleRecordComplexF32(
    handle, b'', 0, number_of_samples, 1,
    ctypes.byref(data_array), ctypes.byref(wfm_info)
)

# 检查返回状态(非0通常表示错误)
if status != 0:
    print(f"调用错误,状态码:{status}")
else:
    # 提取real和imag数据
    real_data = [sample.real for sample in data_array]
    imag_data = [sample.imaginary for sample in data_array]
    print(f"获取到{len(real_data)}个采样点")
    # 也可以直接访问单个采样
    print(f"第一个采样:real={data_array[0].real}, imaginary={data_array[0].imaginary}")
    # 打印波形信息
    print(f"实际采样数:{wfm_info.actualSamples}")
    print(f"X增量:{wfm_info.xIncrement}")

注意事项

  • 确保ViSession等类型的定义与NI的头文件一致,比如ViInt64对应ctypes.c_longlong,ViReal64对应ctypes.c_double,避免类型不匹配导致的错误。
  • 调用函数后务必检查返回状态码,非0值表示调用失败,可以根据NI的错误码文档排查问题。

内容的提问来源于stack exchange,提问作者pyNewbie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 07:57:59