简体   繁体   English

我无法使用MemoryStream转换为C#的C ++ memcpy代码

[英]C++ memcpy code that I can't translate to C# with a MemoryStream

I'm trying to write a c++ lib to c# and have a block of code I have no idea how to translate it to c#. 我正在尝试为c#编写一个c ++库,并且有一段代码我不知道如何将它转换为c#。 I first thought it had something to do with a char array but then a long got put into it and I got totally confused. 我首先想到它与一个char数组有关,但后来很长时间被放进去,我完全糊涂了。

    unsigned long TileSize = fh.TileSize;
    char * pDiffBuf = (char*)malloc(TileSize * 4);
    long Diff = 10;
    memcpy((char*)pDiffBuf+zi*4, &Diff, 4);

In one of my previous questions I learned I can use a MemoryStream with a EndianBinaryWriter to do simple stuff like 在我之前的一个问题中,我了解到我可以使用带有EndianBinaryWriter的MemoryStream来完成简单的操作

Memcpy(ScaleBuf, &VertScale, 4);

I create ScaleBuf as a Writer on a MemoryStream and Write out VertScale. 我在MemoryStream上创建ScaleBuf作为Writer并写出VertScale。 But now they are doing some math on the actual buffer ? 但现在他们正在对实际的缓冲区进行一些数学计算? My Ansi C knowledge is to basic for me to read this. 我的Ansi C知识对我来说是基本的。 Can anyone explain to me what he is doing here ? 任何人都可以向我解释他在这里做了什么吗?

I'm guessing he is taking the array of chars (if it is one) that had some memory allocated to earlier. 我猜他正在使用一些字符数组(如果它是一个),它已经分配了一些内存。 and then putting the value of Diff in it. 然后将Diff的值放入其中。 But why the calculation ? 但为何计算? calculate an offset in the array ? 计算数组中的偏移量? I simplified this example btw in the real code that memcpy is part of a for loop and each loop Diff has another value. 我在真实代码中简化了这个例子btw,memcpy是for循环的一部分,每个循环Diff都有另一个值。 The example is just a bit to long to put on here to keep things readable and concise to the point. 这个例子有点长,以便保持可读性和简明扼要。

Update: With the comments supplied and answers I managed to make a translation added below the C++ source here. 更新:通过提供的评论和答案,我设法在这里的C ++源代码下添加了一个翻译。 I'm not sure if I missed anything, and don't exactly know yet how to unit test in C# so I'll first need to read up on that to see how I can test all of this. 我不确定我是否遗漏了任何东西,并且还不知道如何在C#中进行单元测试,所以我首先需要阅读它以了解我如何测试所有这些。 If anyone sees a mistake I made I'll be happy to hear of it and I hope this will help others out as well. 如果有人看到我犯了一个错误,我会很高兴听到它,我希望这也会帮助其他人。

Entire code for reference 整个代码供参考

long hfzWriteTile2(hfzFile* fs, hfzHeader& fh, unsigned long TileX, unsigned long TileY, float* pTileData) {

    if(!fs)
        return LIBHFZ_ERROR_INVALID_HANDLE;

    if(!pTileData)
        return LIBHFZ_ERROR_INVALID_HANDLE;

    unsigned long i, j;
    long TempInt;
    float f;
    float HFmin, HFmax;
    char c;
    short s;
    unsigned long i1, j1, i2, j2, bnx, bny, zi;
    long FirstVal;
    float VertScale;
    float VertOffset;

    unsigned long nx = fh.nx;
    unsigned long ny = fh.ny;
    unsigned long TileSize = fh.TileSize;
    float Precis = fh.Precis;


    i1 = TileX * TileSize;
    j1 = TileY * TileSize;
    i2 = i1 + TileSize;
    j2 = j1 + TileSize;

    if(i2>=nx)  i2 = nx;
    if(j2>=ny)  j2 = ny;

    bnx = i2 - i1;
    bny = j2 - j1;

    // prepare buffer for line
    char * pDiffBuf = (char*)hfzMalloc(TileSize * 4);
    if(!pDiffBuf) {
        return LIBHFZ_ERROR_ALLOC_FAILED;
    }
    char * pOutBuf = (char*)hfzMalloc(TileSize * 4);
    if(!pOutBuf) {
        return LIBHFZ_ERROR_ALLOC_FAILED;
    }

    // get min/max alt in block (used for vert scale)
    HFmin = 0;
    HFmax = 0;
    for(j=j1; j<j2; j++) {
    for(i=i1; i<i2; i++) {
        // find max diff in line

        f = pTileData[(i-i1) + (j-j1) * fh.TileSize];

        if(j==j1 && i==i1) {
            HFmin = HFmax = f;
        } else {
            if(f<HFmin) HFmin = f;
            if(f>HFmax) HFmax = f;
        }
    }
    }

    // number of int levels required for this block
    float BlockLevels = (HFmax - HFmin) / Precis + 1;

    // calc scale
    VertScale = (HFmax - HFmin)/(float)BlockLevels;
    VertOffset = HFmin;
    if(VertScale<=0)    VertScale = 1.0f; // this is for niceness

    // write the block scaling
    char ScaleBuf[8];
    hfzMemcpy(ScaleBuf, &VertScale, 4);
    hfzMemcpy(ScaleBuf+4, &VertOffset, 4);

    // swap byte order if required (files use little endian)
    if(LIBHFZ_BYTEORDER_BIGENDIAN==hfzByteOrder) {
        hfzByteSwap(ScaleBuf, 4);
        hfzByteSwap(ScaleBuf+4, 4);
    }

    if(8!=hfzWrite(fs, ScaleBuf, 8)) {
        return LIBHFZ_ERROR_WRITE_FAILED;
    }

    // save block line-by-line
    for(j=j1; j<j2; j++) {

        // get first val
        f = pTileData[(j-j1) * fh.TileSize];
        FirstVal = (long)((f-VertOffset)/VertScale);
        long LastVal = FirstVal;

        // find max diff in line
        long Diff;
        long MaxDev = 0;
        for(i=i1+1; i<i2; i++) {

            // find max diff in line
            f = pTileData[(i-i1) + (j-j1) * fh.TileSize];

            TempInt=(long)((f-VertOffset)/VertScale);
            Diff = TempInt - LastVal;

            zi = i-i1-1;
            hfzMemcpy((char*)pDiffBuf+zi*4, &Diff, 4);

            LastVal = TempInt;

            MaxDev = MaxDev>abs(Diff)?MaxDev:abs(Diff);
        }

        // should we use 8, 16 or 32 bit pixels?
        char LineDepth = 4;
        if(MaxDev<=127) {
            LineDepth = 1;
        } else
        if(MaxDev<=32767) {
            LineDepth = 2;
        }

        // write line header
        char BlockBuf[5];
        hfzMemcpy(BlockBuf, &LineDepth, 1); // store line depth
        hfzMemcpy(BlockBuf+1, &FirstVal, 4); // store first value (32bit precis)
        if(LIBHFZ_BYTEORDER_BIGENDIAN==hfzByteOrder) {
            hfzByteSwap(BlockBuf+1, 4);
        }
        if(5!=hfzWrite(fs, BlockBuf, 5)) {
            return LIBHFZ_ERROR_WRITE_FAILED;
        }

        // now write block
        char* pOutBuf2 = pOutBuf;
        for(i=i1+1; i<i2; i++) {

            zi = i-i1-1;
            hfzMemcpy(&Diff, (char*)pDiffBuf+zi*4, 4);
            switch(LineDepth) {
            case 1:
                c = (char)Diff;
                hfzMemcpy(pOutBuf2, &c, LineDepth);
                break;
            case 2:
                s = (short)Diff;
                hfzMemcpy(pOutBuf2, &s, LineDepth);
                break;
            case 4:
                hfzMemcpy(pOutBuf2, &Diff, LineDepth);
                break;
            }

            if(LIBHFZ_BYTEORDER_BIGENDIAN==hfzByteOrder) {
                hfzByteSwap(pOutBuf2, LineDepth);
            }

            pOutBuf2+=LineDepth;
        }

        long len = LineDepth * (i2-i1-1);
        if(len!=hfzWrite(fs, pOutBuf, len))
            return LIBHFZ_ERROR_WRITE_FAILED;
    }

    hfzFree(pDiffBuf);
    hfzFree(pOutBuf);

    return LIBHFZ_STATUS_OK;
}

My C# Translation attempt 我的C#翻译尝试

    public unsafe long hfzWriteTile(HfzFile fs, HfzHeader fh, UInt32 TileX, UInt32 TileY, float[] pMapData) 
    {

        MiscUtil.Conversion.EndianBitConverter endian = MiscUtil.Conversion.EndianBitConverter.Big;
        if (BitConverter.IsLittleEndian)
        {
            endian = MiscUtil.Conversion.EndianBitConverter.Little;
        }

        if(fs != null)
        {
            return LIBHFZ_ERROR_INVALID_HANDLE;
        }

        if(pMapData.Length == 0)
        {
            return LIBHFZ_ERROR_INVALID_HANDLE;
        }

        UInt32 i, j;
        Int32 TempInt;
        float f;
        float HFmin, HFmax;
        char c;
        short s;
        UInt32 i1, j1, i2, j2, bnx, bny, zi;
        Int32 FirstVal;
        float VertScale;
        float VertOffset;

        UInt32 nx = fh.nx;
        UInt32 ny = fh.ny;
        UInt32 TileSize = fh.TileSize;
        float Precis = fh.Precis;

        i1 = TileX * TileSize;
        j1 = TileY * TileSize;
        i2 = i1 + TileSize;
        j2 = j1 + TileSize;

        if(i2>=nx)
        {
            i2 = nx;
        }

        if(j2>=ny)
        {
            j2 = ny;
        }

        bnx = i2 - i1;
        bny = j2 - j1;

        // prepare buffer for line        
        Int32[] pDiffBuf = new Int32[TileSize * 4];

        // get min/max alt in block (used for vert scale)
        HFmin = 0;
        HFmax = 0;
        for(j=j1; j<j2; j++) 
        {
            for(i=i1; i<i2; i++) 
            {
                // find max diff in line

                f = pMapData[i + j * nx];

                if(j==j1 && i==i1) 
                {
                    HFmin = HFmax = f;
                } 
                else 
                {
                    if(f<HFmin) HFmin = f;
                    if(f>HFmax) HFmax = f;
                }
            }
        }

        // number of int levels required for this block
        float BlockLevels = (HFmax - HFmin) / Precis + 1;

        // calc scale
        VertScale = (HFmax - HFmin)/(float)BlockLevels;
        VertOffset = HFmin;
        if(VertScale<=0)    VertScale = 1.0f; // this is for niceness

        // write the block scaling
        MemoryStream ScaleBuf = new MemoryStream();
        EndianBinaryWriter ScaleBufWriter = new EndianBinaryWriter(endian, ScaleBuf);

        ScaleBufWriter.Write(VertScale);
        ScaleBufWriter.Write(VertOffset);
        Util.CopyStream(ScaleBuf, fs.pIoStream);
        ScaleBuf.Close();
        ScaleBufWriter.Close();

        // save block line-by-line
        for(j=j1; j<j2; j++) {

            // get first val
            f = pMapData[i1 + j * nx];
            FirstVal = (Int32)((f-VertOffset)/VertScale);
            Int32 LastVal = FirstVal;

            // find max diff in line
            Int32 Diff;
            Int32 MaxDev = 0;
            for(i=i1+1; i<i2; i++) {

                // find max diff in line
                f = pMapData[i + j * nx];

                TempInt=(Int32)((f-VertOffset)/VertScale);
                Diff = TempInt - LastVal;

                zi = i-i1-1;
                pDiffBuf[zi * 4] = Diff;

                LastVal = TempInt;

                MaxDev = MaxDev > Math.Abs(Diff) ? MaxDev : Math.Abs(Diff);
            }

            // should we use 8, 16 or 32 bit pixels?
            char LineDepth = '4';
            if(MaxDev<=127) {
                LineDepth = '1';
            } else
            if(MaxDev<=32767) {
                LineDepth = '2';
            }

            // write line header
            MemoryStream BlockBuf = new MemoryStream();
            EndianBinaryWriter BlockBufWriter = new EndianBinaryWriter(endian, BlockBuf);

            BlockBufWriter.Write(LineDepth);
            BlockBufWriter.Write(FirstVal);
            Util.CopyStream(BlockBuf, fs.pIoStream);
            BlockBuf.Close();
            BlockBufWriter.Close();

            // now write block
            MemoryStream pOutBuf = new MemoryStream();
            EndianBinaryWriter pOutBufWriter = new EndianBinaryWriter(endian, pOutBuf);

            for(i=i1+1; i<i2; i++) {

                zi = i-i1-1;
                Diff = pDiffBuf[zi*4];
                switch(LineDepth) 
                {
                    case '1':
                        c = (char)Diff;
                        pOutBufWriter.Write(c);
                        break;
                    case '2':
                        s = (short)Diff;
                        pOutBufWriter.Write(s);
                        break;
                    case '4':
                        pOutBufWriter.Write(Diff);
                        break;
                }
            }

            Util.CopyStream(pOutBuf, fs.pIoStream);
            pOutBuf.Close();
            pOutBufWriter.Close();
        }

        return LIBHFZ_STATUS_OK;
    }

Basically, it creates a char array, and then copies the 10 value (the first four bytes of the long, whatever they are - that depends on endianness) to a given position in that char array. 基本上,它创建一个char数组,然后将10值(长的前四个字节,无论它们是什么 - 取决于字节顺序)复制到该char数组中的给定位置。

Basically, think of the pointer + zi * 4 as indexing in an array. 基本上,将pointer + zi * 4视为数组中的索引。 If pDiffBuf was a byte array, this would be the same as saying pDiffBuff[zi * 4] . 如果pDiffBuf是一个字节数组,这与pDiffBuff[zi * 4]

I don't see how this could be useful. 我不知道这有什么用。 Could you show some more of the code? 你能展示更多的代码吗?

What you're trying to do is unsafe. 你要做的是不安全。

http://msdn.microsoft.com/en-us/library/chfa2zb8.aspx http://msdn.microsoft.com/en-us/library/chfa2zb8.aspx

I don't mean don't do it. 我不是说不要这样做。 I mean it's unsafe . 我的意思是它unsafe Start with something like this: 从这样的事情开始:

unsafe void hfzWriteTile2 (hfzFile* fs, hfzHeader* fh,
  UInt64 TileX, UInt64 TileY, float* pTileData)
{
}

The main thing that the unsafe keyword gives you is the ability to manipulate data directly through pointers. unsafe关键字为您提供的主要功能是能够通过指针直接操作数据。 Here's a really basic introduction on how that works. 这是一个关于它是如何工作的真正基本的介绍。

http://msdn.microsoft.com/en-us/library/y31yhkeb.aspx http://msdn.microsoft.com/en-us/library/y31yhkeb.aspx

sigh I have to go do my job now. 感叹我现在必须去做我的工作。 I'll come back to this later today and see how you're doing with it. 我今天晚些时候回到这里,看看你是如何做到的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM