代码之家  ›  专栏  ›  技术社区  ›  Dmitry

在C中容纳嵌套的不安全结构#

  •  3
  • Dmitry  · 技术社区  · 11 年前

    满足以下条件的最佳方式是什么:

    实时、性能关键的应用程序,与本机C dll接口,用于与专有后端通信。

    原生api有成百上千的结构、嵌套结构和通过这些结构来回传递数据的方法。

    想要使用c#进行逻辑,所以决定使用不安全的c#来支持cli和封送处理。我知道是如何实现的,并且已经通过后面的实现了,所以请不要回复“使用cli”。每秒对数百个结构进行一百次编组会带来足够大的延迟,因此有必要调查不安全的c#。

    大多数c结构都包含几十个字段,因此要寻找一种方法来对每个字段进行最少的键入。在这一点上,我们需要运行一个VS宏,在必要时将每个行元素转换为c#等效的设置数组,以固定大小。在我找到嵌套的结构数组之前,这项工作非常好。例如,我有以下两个结构:

    [StructLayout(LayoutKind.Sequential,Pack=1)]
    unsafe struct User{
        int id;
        fixed char name[12];
    }
    
    [StructLayout(LayoutKind.Sequential,Pack=1)]
    unsafe structs UserGroup{
        fixed char name[12];
        fixed User users[512]
        int somethingElse;
        fixed char anotherThing[16]
    }
    

    什么是容纳固定用户[512]的最佳方式,以便在运行时不必做太多事情?

    我看过建议应该做的例子

    [StructLayout(LayoutKind.Sequential,Pack=1)]
    unsafe structs UserGroup{
        fixed char name[12];
        User users_1;
        User users_2;
        ...
        User users_511;
        int somethingElse;
        fixed char anotherThing[16]
    }
    

    另一个想法是,以字节为单位计算User的大小,然后这样做

    [StructLayout(LayoutKind.Sequential,Pack=1)]
    unsafe structs UserGroup{
        fixed char name[12];
        fixed byte Users[28*512];
        int somethingElse;
        fixed char anotherThing[16]
    }
    

    但这意味着每当我需要使用这个结构时,我都必须对它进行特殊处理,或者用其他代码包装它。api中有足够多的东西,我想避免这种方法,但如果有人能展示一种优雅的方式,我也可以这样做

    第三种方法让我很困惑,以至于我无法制作和举例(我想我在某个地方看到了,但再也找不到了),那就是为User指定大小,或者以某种方式使其严格大小,这样你就可以在上面使用“固定”关键字。

    有人能推荐一种合理的方法吗?他们已经使用了这种方法,并且在负载下可以很好地扩展?

    1 回复  |  直到 11 年前
        1
  •  1
  •   Dmitry    11 年前

    我能在不安全的结构中找到嵌套结构的最好方法是将它们定义为固定字节数组,然后为字段提供运行时转换属性。例如:

    [StructLayout(LayoutKind.Sequential,Pack=1)]
    unsafe struct UserGroup{
        fixed char name[12];
        fixed User users[512]
        int somethingElse;
        fixed char anotherThing[16]
    }
    

    转化为:

    [StructLayout(LayoutKind.Sequential,Pack=1)]
    unsafe struct UserGroup{
        fixed char name[12];
        fixed byte users[512 * Constants.SizeOfUser]
        int somethingElse;
        fixed char anotherThing[16];
        public User[] Users
        {
            get
            {
                var retArr = new User[512];
                fixed(User* retArrRef = retArr){
                    fixed(byte* usersFixed = users){
                        {
                            Memory.Copy(usersFixed, retArrRef,  512 * Constants.SizeOfUser);
                        }
                    }
                }
                return retArr;
            }
        }
    }
    

    请注意,此代码使用此处提供的Memory.Copy功能: http://msdn.microsoft.com/en-us/library/aa664786(v=vs.71).aspx

    geter的一般解释如下:

    1. 为返回值分配托管数组
    2. 获取并修复指向它的不安全指针
    3. 获取并修复指向结构的字节数组的不安全指针
    4. 将内存从一个复制到另一个

    托管数组没有存储回其自身的结构中的原因是,它会修改布局,无法再正确转换,而从非托管数组中获取道具则没有问题。或者,可以将其封装在另一个进行存储的托管对象中。