【问题标题】:safe fixed size array in struct c#struct c#中的安全固定大小数组
【发布时间】:2018-02-27 00:16:42
【问题描述】:

我在一个嵌入式 MCU 中有一个 C 结构体,大约有 1000 个元素,它内部包含许多固定大小的数组和其他结构体,现在我想使用 C# 将数据带到 PC 上

这是我在 C 中的结构元素的简单预览

struct _registers
{
    char name[32];
    float calibrate[4][16];
    float DMTI;
    float DMTII;
    float DMTIII;
    float DMTIE;
    float DMTIIE;
    ....
};

现在我想使用 GCHandle 类将 Struct 转换为 C#,

类似的东西

//The C struct is in this byte array named buffer
byte[] buffer = new byte[4096];

        GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
       _registers stuff = (protection_registers)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),typeof(_registers));
        handle.Free();

问题在于 Visual Studio 抱怨“指针和固定大小的缓冲区只能在不安全的上下文中使用”

有没有办法在没有不安全代码的情况下正常使用它?我发现做这样的事情

[StructLayout(LayoutKind.Explicit, Size = 56, Pack = 1)]
public struct NewStuff
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    [FieldOffset(0)]
    public string name;

    [MarshalAs(UnmanagedType.U4)]
    [FieldOffset(32)]
    public float calibrate[4][16];
}

但是随着 MCU 上的代码在未来几年不断发展,我们将在 Struct 中添加大量功能和参数,而且由于 struct 已经有 1000 个元素,我们如何才能做得更好、更聪明呢?因为跟踪所有偏移量非常困难且容易出错!

【问题讨论】:

  • 标签垃圾邮件是不好的网络礼仪
  • 您不需要指定FieldOffset,只要您正确定义了所有字段的大小(您正在这样做)。
  • 如果 _registers 有 1000 个元素,则不应将其声明为 struct。改为将其声明为class。否则,每个分配都会创建一个新的_registers 副本。 C++中classstruct的区别与C#中classstruct的区别不一样。
  • 有没有办法把 SizeConst 也去掉?
  • 谢谢,能给我一个狙击密码吗?

标签: c# arrays struct


【解决方案1】:

尝试做这样的事情(注意:使用 class 而不是 struct 更适合 C# - 仍然可以将 OK 编组为 C++ 结构):

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class NewStuff
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public StringBuilder name;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4*16)]
    public float[,] calibrate;

    [MarshalAs(UnmanagedType.R4)]
    public float DMTI;

    [MarshalAs(UnmanagedType.R4)]
    public float DMTII;

    // Etc
}

您将无法删除 SizeConst,因为编组需要知道这一点。

此外,当您初始化类时,您需要将数组字段设置为适当大小的缓冲区,并使用正确的缓冲区大小初始化 StringBuilder

这样做意味着您可以避免使用fixed 缓冲区(因此,您可以避免使用unsafe 代码)。

【讨论】:

  • [FieldOffset] 并非不安全。他的代码 sn-p 很糟糕,它缺少 fixed 关键字。需要使其编译。固定大小的缓冲区是不安全的,不检查索引它们。
  • @HansPassant 是的,我删除了关于 FieldOffset 的 cmets。我记错了 someone proposed that FieldOffset should be unsafe 的旧讨论 - 但当然,这从未发生过......
  • @HansPassant [FieldOffset] 可用于破坏 .NET 的类型安全,至少在引用类型中如此,因此允许类型双关(也不是特别有用的类型双关......),但这怎么“不安全”?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-15
  • 2012-03-17
  • 2020-08-12
  • 1970-01-01
  • 2017-08-27
  • 2016-10-29
  • 1970-01-01
相关资源
最近更新 更多