C++不规则C风格二维数组转二维vector的编译错误及C#交互问题
解决C风格不规则二维数组转vector的编译错误及C#调用DLL的封送问题
一、C++编译错误修复
核心问题分析
- 指针无法获取数组长度:
sizeof points0 / sizeof points0[0]这类写法完全错误——points0是指针,sizeof(points0)得到的是指针本身的字节数(64位系统为8),不是数组元素数量;同理sizeof faces0[i]也无法获取子数组的长度。 - vector构造类型不匹配:
std::vector<std::vector<int>> faces1(faces0, ...)的范围构造函数要求迭代器指向vector<int>类型,但faces0是int**,指向的是int*,类型不兼容,直接触发编译错误。
修复后的C++代码
必须让调用方传入点数组长度、面数组数量、每个面的顶点数数组(因为是不规则二维数组,子数组长度各不相同):
#include <vector> // 假设Point_3和Polygon_mesh是已定义的类型 struct Point_3 { double x, y, z; }; class Polygon_mesh {}; bool read_polygon_mesh_core(std::vector<Point_3>&, std::vector<std::vector<int>>&, Polygon_mesh&); // 修正后的对外接口:增加长度参数 bool read_polygon_mesh(Point_3* points0, size_t point_count, int** faces0, size_t face_count, const size_t* face_vertex_counts, Polygon_mesh& polygon_mesh) { // 正确构造点vector:用指针+显式长度 std::vector<Point_3> points(points0, points0 + point_count); std::vector<std::vector<int>> faces1; faces1.reserve(face_count); // 预分配空间提升效率 for (size_t i = 0; i < face_count; ++i) { // 根据传入的顶点数构造子vector std::vector<int> face(faces0[i], faces0[i] + face_vertex_counts[i]); faces1.push_back(std::move(face)); // 用move避免不必要的拷贝 } return read_polygon_mesh_core(points, faces1, polygon_mesh); }
二、C#与C++ DLL的交互解决方案
核心问题分析
C#的泛型List<T>无法直接封送到C++——.NET封送器不支持泛型类型;同时C++的int**和C#的嵌套List没有直接映射关系,必须使用blittable类型(可直接在托管/非托管内存间转换的类型,如数组、简单结构体)。
方案1:使用交错数组适配C++的int**
步骤1:C++导出函数(需用extern "C"避免名字 mangling)
extern "C" __declspec(dllexport) bool read_polygon_mesh_export( Point_3* points0, size_t point_count, int** faces0, size_t face_count, const size_t* face_vertex_counts, Polygon_mesh* polygon_mesh // 若需返回数据,用指针传递 ) { Polygon_mesh temp_mesh; bool result = read_polygon_mesh(points0, point_count, faces0, face_count, face_vertex_counts, temp_mesh); // 若需将mesh返回给C#,此处需手动复制数据到polygon_mesh指针指向的内存 return result; }
步骤2:C#调用代码
using System; using System.Runtime.InteropServices; namespace DLLimport { internal class Program { // C++的size_t对应C#的UIntPtr(跨平台兼容) [DllImport("region_growing_planes_on_polygon_mesh.dll", CallingConvention = CallingConvention.Cdecl)] static extern bool read_polygon_mesh_export( [In] Point_3[] points, UIntPtr pointCount, [In] int[][] faces, UIntPtr faceCount, [In] UIntPtr[] faceVertexCounts, IntPtr polygonMesh // 用IntPtr封装非托管对象 ); // 必须定义为结构体,且字段公开、布局连续(blittable要求) [StructLayout(LayoutKind.Sequential)] public struct Point_3 { public double x; public double y; public double z; public Point_3(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } } static void Main(string[] args) { var points = new Point_3[] { new Point_3(10, 10, 10), new Point_3(20, 20, 10), new Point_3(30, 30, 10) }; // 交错数组对应C++的int** var faces = new int[][] { new int[] { 0, 1, 2 } // 注意:C++通常用0索引,需与业务逻辑匹配 }; // 每个面的顶点数数组 var faceVertexCounts = new UIntPtr[] { UIntPtr.FromUInt32(3) }; // 若需接收C++返回的Polygon_mesh,需提前分配非托管内存 IntPtr polygonMesh = IntPtr.Zero; bool result = read_polygon_mesh_export( points, (UIntPtr)points.Length, faces, (UIntPtr)faces.Length, faceVertexCounts, polygonMesh ); // 后续处理:释放非托管内存(若有分配) } } }
方案2:Flatten成一维数组(更高效,适合大数据场景)
将所有面的顶点数据合并到一个一维数组,配合顶点数数组传递,避免嵌套指针的封送复杂度:
C++导出函数
extern "C" __declspec(dllexport) bool read_polygon_mesh_flat( Point_3* points0, size_t point_count, int* faces_flat, size_t face_count, const size_t* face_vertex_counts, Polygon_mesh* polygon_mesh ) { std::vector<Point_3> points(points0, points0 + point_count); std::vector<std::vector<int>> faces1; faces1.reserve(face_count); size_t offset = 0; for (size_t i = 0; i < face_count; ++i) { size_t count = face_vertex_counts[i]; std::vector<int> face(faces_flat + offset, faces_flat + offset + count); faces1.push_back(std::move(face)); offset += count; } Polygon_mesh temp_mesh; bool result = read_polygon_mesh_core(points, faces1, temp_mesh); // 复制数据到polygon_mesh(若需要) return result; }
C#调用代码
[DllImport("region_growing_planes_on_polygon_mesh.dll", CallingConvention = CallingConvention.Cdecl)] static extern bool read_polygon_mesh_flat( [In] Point_3[] points, UIntPtr pointCount, [In] int[] facesFlat, UIntPtr faceCount, [In] UIntPtr[] faceVertexCounts, IntPtr polygonMesh ); // Main方法中使用: var facesFlat = new int[] { 0, 1, 2 }; var faceVertexCounts = new UIntPtr[] { UIntPtr.FromUInt32(3) }; bool result = read_polygon_mesh_flat( points, (UIntPtr)points.Length, facesFlat, (UIntPtr)1, faceVertexCounts, polygonMesh );
关键注意事项
- 长度必须显式传递:C++指针无法获取数组长度,所有数组/子数组的长度都需要调用方主动传入。
- 类型匹配:C++的
size_t对应C#的UIntPtr,避免32/64位平台的兼容性问题。 - blittable类型限制:C#传递给DLL的类型必须是 blittable(如结构体、数组),泛型集合直接封送会失败。
内容的提问来源于stack exchange,提问作者Aura4
相关产品推荐
相关产品推荐

