【问题标题】:Getting address of a struct获取结构体地址
【发布时间】:2017-10-12 10:24:29
【问题描述】:

这是我的代码:

using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using System;
using System.IO;

public class CarMove : MonoBehaviour
{
public unsafe struct TrafficRoadSystem { };
public unsafe struct CarsSimulation { };
public unsafe struct CarPostion
{
    double position_x;
    double position_y;
    double position_z;
};

// Use this for initialization
[DllImport("Assets/traffic.dll", CharSet = CharSet.Ansi)]
public unsafe static extern int traffic_import_osm([MarshalAs(UnmanagedType.LPStr)] string osm_pbf_path, TrafficRoadSystem** out_road_system);
[DllImport("Assets/traffic.dll")]
public unsafe static extern int create_simulation(TrafficRoadSystem* road_system, CarsSimulation** out_simulation, double speed, int cars_count);
[DllImport("Assets/traffic.dll")]
public static extern void update_simulation(ref CarsSimulation simulation, double time);
[DllImport("Assets/traffic.dll")]
public static extern CarPostion get_car_postion(ref CarsSimulation simulation, int car_number);
unsafe CarsSimulation* carSimulation;
unsafe TrafficRoadSystem* trafficRoadSystem;
void Start()
{
    unsafe
    {
        string osmPath = "Assets/Resources/map.osm.pbf";
        int results;
        results = traffic_import_osm(osmPath, &trafficRoadSystem);
    }
}

// Update is called once per frame
void Update()
{

}
}

这是来自 dll C 库。函数int traffic_import_osm() 作用于TrafficRoadSystem* trafficRoadSystem; 对象作为参考,我想访问void Update() 中的对象。这在一个函数中运行良好,但我无法获取类变量的地址并且出现错误

Error CS0212 You can only take the address of an unfixed expression inside of a fixed statement initializer

在线results = traffic_import_osm(osmPath, &trafficRoadSystem);

我尝试使用此解决方案 https://msdn.microsoft.com/en-us/library/29ak9b70(v=vs.90).aspx

这是我写的:

TrafficRoadSystem trafficRoadSystem;
void Start()
{
    unsafe
    {
        string osmPath = "Assets/Resources/map.osm.pbf";
        CarMove carMove = new CarMove();
        int results;
        fixed( TrafficRoadSystem* ptr = &carMove.trafficRoadSystem)
        {
            results = traffic_import_osm(osmPath, &ptr);
        }
    }
}

我在行中收到错误CS0459 Cannot take the address of a read-only local variable results = traffic_import_osm(osmPath, &ptr);

【问题讨论】:

  • 您不能只是复制/粘贴 C 声明并希望它会起作用。该函数很难从 C 程序中调用,当您必须调用它时,它永远不会变得更好。它看起来 像是在尝试返回对数组的引用。但是要使用它,您必须知道数组中的元素数量,也许 int 返回值会告诉您这一点。您无法判断是否应该释放数组的内存。您唯一的希望是元素上的 IntPtr 和 Marshal.PtrToStructure 。但你最好先索要编程手册。

标签: c# unity3d dll dllimport


【解决方案1】:

在 Unity 中制作 C 或 C++ 插件需要对这些语言有广泛的了解。这意味着您应该在尝试在 Unity 中使用原始指针之前花时间学习指针。因为即使你让它编译,你也可能会遇到难以修复的崩溃。

你有:

unsafe TrafficRoadSystem* trafficRoadSystem;

并希望将其传递给下面的函数:

public unsafe static extern int traffic_import_osm(..., TrafficRoadSystem** out_road_system);

1.trafficRoadSystem 变量是一个指针,您需要创建另一个指向trafficRoadSystem 的指针。这被称为“指向指针的指针”

TrafficRoadSystem** addressOfTrafficRoadSystem = &trafficRoadSystem;

注意双“**”。

2。您必须使用fixed 关键字来执行我在#1 中提到的操作。

fixed (TrafficRoadSystem** addressOfTrafficRoadSystem = &trafficRoadSystem)
{

}

3。您可以将该指向指针地址的指针传递给traffic_import_osm 函数。

全新的启动功能:

void Start()
{
    unsafe
    {
        fixed (TrafficRoadSystem** addressOfTrafficRoadSystem = &trafficRoadSystem)
        {
            string osmPath = "Assets/Resources/map.osm.pbf";
            int results;
            results = traffic_import_osm(osmPath, addressOfTrafficRoadSystem);
        }
    }
}

未来可能出现的不相关问题:

1。我注意到您在更新后的问题中使用了CarMove carMove = new CarMove();。不要在这里使用new 关键字,因为CarMove 继承自MonoBehaviour。请参阅this 答案了解该怎么做。

2。我还注意到您使用了"Assets/Resources/map.osm.pbf";。构建项目时,此路径将无效。考虑使用 StreamingAssets 文件夹,而不是仅适用于 Resources API 的 Resources 文件夹。您将 Application.streamingAssetsPathStreamingAssets 文件夹一起使用。

【讨论】:

    【解决方案2】:

    使用原始指针的替代方法是使用编组。编组允许您采用 C# 数据结构并将它们转换为 C 可理解的数据,而无需任何不安全的关键字。

    Mono 有一个 document 描述如何使用 PInvoke(这是您要查找的搜索词)与本机库正确交互。

    Hereherehere 您还可以找到 PInvoke 和 Marshalling 的介绍。

    基本上,您将指针签名替换为IntPtr-type,它是指针的托管版本。要转换托管结构变量,您首先需要分配一个内存区域并将其用于您的结构

    IntPtr ptr;
    TrafficRoadSystem _struct;
    try {
        ptr = Marshal.AllocHGlobal(Marshal.SizeOf(_struct));
        Marshal.StructureToPtr(_struct, ptr, false);
    } finally {
        Marshal.FreeHGlobal(ptr);
    }
    

    虽然我不知道如何正确处理双指针..

    【讨论】:

      猜你喜欢
      • 2016-01-09
      • 2010-11-19
      • 2016-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多