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

C++不规则C风格二维数组转二维vector的编译错误及C#交互问题

解决C风格不规则二维数组转vector的编译错误及C#调用DLL的封送问题

一、C++编译错误修复

核心问题分析

  1. 指针无法获取数组长度:sizeof points0 / sizeof points0[0]这类写法完全错误——points0是指针,sizeof(points0)得到的是指针本身的字节数(64位系统为8),不是数组元素数量;同理sizeof faces0[i]也无法获取子数组的长度。
  2. 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
);

关键注意事项

  1. 长度必须显式传递:C++指针无法获取数组长度,所有数组/子数组的长度都需要调用方主动传入。
  2. 类型匹配:C++的size_t对应C#的UIntPtr,避免32/64位平台的兼容性问题。
  3. blittable类型限制:C#传递给DLL的类型必须是 blittable(如结构体、数组),泛型集合直接封送会失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:23:17