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

Python通过ctypes调用Fortran处理对象数组时访问冲突错误的解决咨询

问题修复与代码优化

错误根源

  1. Python指针传递错误:你错误地传递了数组指针的地址,而非数组的起始地址。ct.byref(arr_ptr)会创建指向指针的指针,但Fortran的C_F_POINTER期望直接接收指向结构体数组的C指针。
  2. Fortran内存非法释放:my_array是通过C_F_POINTER绑定的外部Python内存,并非Fortran自行分配的内存,调用deallocate(my_array)会触发内存访问违规。

修正后的Python代码

import ctypes as ct
import os
import numpy as np

here = os.path.dirname(__file__)
lib_file = os.path.abspath(os.path.join(here, '..', 'fortran', 'svector_test_mod.dll'))
fortlib = ct.CDLL(lib_file, winmode=0)

class StateVector(ct.Structure):
    _fields_ = [
        ('x', ct.c_longdouble),
        ('y', ct.c_longdouble),
        ('z', ct.c_longdouble),
        ('vx', ct.c_longdouble),
        ('vy', ct.c_longdouble),
        ('vz', ct.c_longdouble),
        ('t', ct.c_longdouble),
    ]

# 显式声明Fortran函数参数类型,避免类型不匹配
fortlib.lists_change.argtypes = [ct.POINTER(StateVector), ct.c_int]
fortlib.lists_change.restype = None

size = 5
array = (StateVector * size)()

for i in range(size):
    array[i].x = ct.c_longdouble(2.5)
    array[i].y = ct.c_longdouble(2.5)
    array[i].z = ct.c_longdouble(2.5)
    array[i].vx = ct.c_longdouble(2.5)
    array[i].vy = ct.c_longdouble(2.5)
    array[i].vz = ct.c_longdouble(2.5)
    array[i].t = ct.c_longdouble(2.5)

# 直接获取结构体数组的指针
arr_ptr = ct.cast(array, ct.POINTER(StateVector))
# 也可以用numpy数组方式:
# np_objects = np.ctypeslib.as_array(array)
# arr_ptr = np_objects.ctypes.data_as(ct.POINTER(StateVector))

fortlib.lists_change(arr_ptr, size)

# 验证处理结果
for i in range(size):
    print(f"第{i+1}个元素: x={array[i].x}, y={array[i].y}, z={array[i].z}, vx={array[i].vx}, vy={array[i].vy}, vz={array[i].vz}, t={array[i].t}")

修正后的Fortran代码

module state_vector_mod
    use, intrinsic :: iso_c_binding, only: C_LONG_DOUBLE, c_int, C_PTR, C_F_POINTER
    implicit none

    type, bind(C) :: state_vector
        real(C_LONG_DOUBLE) :: x
        real(C_LONG_DOUBLE) :: y
        real(C_LONG_DOUBLE) :: z
        real(C_LONG_DOUBLE) :: vx
        real(C_LONG_DOUBLE) :: vy
        real(C_LONG_DOUBLE) :: vz
        real(C_LONG_DOUBLE) :: t
    end type state_vector

contains

    subroutine make_sv(x, y, z, vx, vy, vz, t, sv) bind(c, name='make_sv')
        real(C_LONG_DOUBLE), intent(in) :: x
        real(C_LONG_DOUBLE), intent(in) :: y
        real(C_LONG_DOUBLE), intent(in) :: z
        real(C_LONG_DOUBLE), intent(in) :: vx
        real(C_LONG_DOUBLE), intent(in) :: vy
        real(C_LONG_DOUBLE), intent(in) :: vz
        real(C_LONG_DOUBLE), intent(in) :: t
        type(state_vector), intent(out), target :: sv

        sv = state_vector(x, y, z, vx, vy, vz, t)
    end subroutine make_sv

    subroutine lists_change(in_list, length) bind(C, name='lists_change')
        type(C_PTR), intent(in) :: in_list  ! 指针本身无需修改,用intent(in)
        type(state_vector), dimension(:), pointer :: my_array
        integer(c_int), intent(in) :: length
        integer(c_int) :: i

        ! 将C指针绑定为Fortran可访问的数组指针
        call C_F_POINTER(in_list, my_array, [length])

        DO i = 1, length
            my_array(i)%x = my_array(i)%x * 2
            my_array(i)%y = my_array(i)%y * 2
            my_array(i)%z = my_array(i)%z * 2
            my_array(i)%vx = my_array(i)%vx * 2
            my_array(i)%vy = my_array(i)%vy * 2
            my_array(i)%vz = my_array(i)%vz * 2
            my_array(i)%t = my_array(i)%t * 2
        END DO

        ! 移除非法的deallocate语句,内存由Python管理
    end subroutine lists_change
end module state_vector_mod

关键优化说明

  • Python端:必须显式声明argtypes,避免参数类型自动转换引发的内存错误;直接传递结构体数组指针,无需额外包装。
  • Fortran端:删除deallocate(my_array),该数组内存由Python负责;将in_list的intent改为in,因为仅需访问指针指向的内存,无需修改指针本身。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 15:43:18