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; }
解决方案
- 修正
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);
- 修正
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);
- 严格检查NetCDF函数错误码
每次调用NetCDF函数后,检查errorid是否为NC_NOERR(0),确保函数调用真正成功,避免基于错误状态执行后续操作。
内容的提问来源于stack exchange,提问作者FSnowman
相关产品推荐
相关产品推荐

