为什么我的非托管行李返回错误值?对齐偏移计算可能出现问题

问题描述 投票:0回答:1

我创建了这个非托管包数据持有者,它允许我在严格的非托管上下文中使用它。但是,我认为对齐似乎存在一些问题。我就是不明白那是什么...

这是整个结构代码:

using System;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;

namespace Game.Runtime.Utility
{
    public struct BagUnmanaged : IDisposable
    {
        private NativeList<byte> data;
        private NativeList<int>  offsets;
        
        private int currentOffset;

        public BagUnmanaged(Allocator allocator)
        {
            data    = new NativeList<byte>(allocator);
            offsets = new NativeList<int>(allocator);
            
            currentOffset = 0;
        }

        private int AlignOffset(int offset, int alignment)
        {
            return (offset + (alignment - 1)) & ~(alignment - 1);
        }
        public unsafe void Add<T>(T value) where T : unmanaged
        {
            int size = UnsafeUtility.SizeOf<T>();
            int alignment = UnsafeUtility.AlignOf<T>();
        
            currentOffset = AlignOffset(currentOffset, alignment);

            offsets.Add(currentOffset);

            data.ResizeUninitialized(currentOffset + size);

            byte* ptr = data.GetUnsafePtr();
            UnsafeUtility.CopyStructureToPtr(ref value, ptr + currentOffset);

            currentOffset += size;
        }

        public unsafe T Get<T>(int index) where T : unmanaged
        {
            int   elementOffset = offsets[index];
            byte* ptr           = data.GetUnsafeReadOnlyPtr();
            
            return UnsafeUtility.ReadArrayElementWithStride<T>(ptr, elementOffset, UnsafeUtility.SizeOf<T>());
        }
        public unsafe void Set<T>(int index, T value) where T : unmanaged
        {
            int   elementOffset = offsets[index];
            byte* ptr           = data.GetUnsafePtr();
            
            UnsafeUtility.CopyStructureToPtr(ref value, ptr + elementOffset);
        }

        public void Dispose()
        {
            if (data.IsCreated)
            { data.Dispose(); }
            
            if (offsets.IsCreated)
            { offsets.Dispose(); }
        }
    }
}

我已经测试过它,当我从包里取出它们时,float 和 bool 值似乎都是正确的,但是,添加它和更新后的 int 值完全错误。

private void Start()
{
    using BagUnmanaged bag = new(Allocator.Persistent);
    
    bag.Add(5.0F);
    bag.Add(1);
    bag.Add(true);

    var f = bag.Get<float>(0);
    var i = bag.Get<int>(1);
    var b = bag.Get<bool>(2);
    
    Console.WriteLine("Float {0}", f);
    Console.WriteLine("Int {0}", i); // Returns sometimes 0 sometimes -1 or 80
    Console.WriteLine("Boolean {0}", b);
    
    bag.Set(1, 90);
    
    i = bag.Get<int>(1);
    
    Console.WriteLine("Updated Int {0}", i); // Same incorrect value as above
}
c# unity-game-engine pointers unsafe
1个回答
0
投票

您的问题在于使用

UnsafeUtility.ReadArrayElementWithStride
进行阅读:

ReadArrayElementWithStride(destination, index, stride, value)
是一个只执行
Write(destination + index * stride, value)
功能的函数。 “stride”参数是数组中包含的元素的宽度(假设所有元素的大小相同!),它将与索引相乘。第二个参数不是 offset,而是 index。所以你的阅读越界了。

解决此问题只需将您的阅读逻辑更改为使用

UnsafeUtility.CopyPtrToStructure
,即
UnsafeUtility.CopyStructureToPtr
的对应部分:

public unsafe T Get<T>(int index) where T : unmanaged {
    ...
    UnsafeUtility.CopyPtrToStructure(ptr + elementOffset, out T result);
    return result;
}
© www.soinside.com 2019 - 2024. All rights reserved.