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

C#调用NetCDF C库时Marshal.Copy触发内存保护错误求助

问题:C#调用NetCDF库时Marshal.Copy触发内存保护错误

场景说明

在C#项目中调用C编写的NetCDF库处理NetCDF文件,流程如下:

  • 调用nc_open打开CDF文件:执行正常
  • 调用nc_inq_att获取数组长度:执行正常,得到正确值7(已通过NetCDF官方软件验证)
  • 调用nc_get_att_text获取字符数组指针:执行正常
  • 执行Marshal.Copy将指针指向的内存复制到C#数组时,触发错误:Attempted to read or write protected memory. This is often an indication that other memory is corrupt

已尝试的无效操作:

  • 将char数组改为byte数组,通过ASCII编码转换为字符串,仍触发相同错误
  • 原库为x64版本,项目已设置x64编译,尝试Any CPU模式也无改善

相关代码

初始代码

using System;
using System.Runtime.InteropServices;

namespace test
{
    private class LoadData
    {
        private LoadData()
        { 
            OpenFileDialog File = new OpenFileDialog();
            int ncid;
            int errorid;
            string op_name;

            File.Filter = "File .cdf|*.cdf";
            if (File.ShowDialog() == DialogResult.OK)
            {
                // 打开CDF文件 - 执行正常
                errorid = nc_open(File.FileName, CreateMode.NC_NOWRITE, out ncid);

                // 查询数组长度 - 执行正常,得到正确值7
                errorid = nc_inq_att(ncid, -1, "operator_name", out NcType atttype, out IntPtr attlength);

                // 获取指针 - 执行正常
                errorid = nc_get_att_text(ncid, -1, "operator_name", out IntPtr value);

                // 将指针和长度传入转换方法
                op_name = CharPointerToString(value, attlength.ToInt64());
            }
        }

        // 用于将指针指向的内存转为字符串的方法
        private string CharPointerToString(IntPtr _pointer, long _length)
        {
            string result;
            char[] chars = new char[(int)_length];
            IntPtr pointer = _pointer;
            Marshal.Copy(_pointer, chars, 0, (int)_length); // 此处触发内存保护错误
            return result = new string(chars);
        }

        [DllImport("netcdf.dll")]
        public static extern int nc_open(string _FileName, CreateMode _CreateMode, out int ncid);

        [DllImport("netcdf.dll")]
        public static extern int nc_inq_att(int _ncid, int _varid, string _AttributeName, out NcType _type, out IntPtr _AttributeLength);

        [DllImport("netcdf.dll")]
        public static extern int nc_get_att_text(int _ncid, int _varid, string _AttributeName, out IntPtr _value);
    }
}

修改后的CharPointerToString方法

private string CharPointerToString(IntPtr _pointer, long _length)
{
   string result;
   byte[] bytes = new byte[(int)_length];
   Marshal.Copy(_pointer, bytes, 0, (int)_length);
   result = Encoding.ASCII.GetString(bytes);
   return result;
}

解决方案

  1. 修正nc_get_att_text的DllImport声明
    NetCDF的nc_get_att_text函数要求传入用户预先分配的缓冲区,而非返回库分配的指针。原声明中使用out IntPtr _value是错误的,正确做法是传入byte数组作为缓冲区:
[DllImport("netcdf.dll")]
public static extern int nc_get_att_text(int ncid, int varid, string name, byte[] buf);

调用示例:

// 在获取到attlength后执行
byte[] buffer = new byte[(int)attlength.ToInt64()];
errorid = nc_get_att_text(ncid, -1, "operator_name", buffer);
op_name = Encoding.ASCII.GetString(buffer);
  1. 修正nc_inq_att的长度参数类型
    nc_inq_att的长度参数实际是size_t*类型,在C#中应使用out long而非IntPtr,避免类型转换导致的长度值异常:
[DllImport("netcdf.dll")]
public static extern int nc_inq_att(int ncid, int varid, string name, out NcType type, out long length);
  1. 严格检查NetCDF函数错误码
    每次调用NetCDF函数后,检查errorid是否为NC_NOERR(0),确保函数调用真正成功,避免基于错误状态执行后续操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 20:13:20