c# - 我无法使用 MemoryStream 将 C++ memcpy 代码转换为 C#

标签 c# c++

我正在尝试将 C++ 库编写为 C#,但有一段代码我不知道如何将其转换为 C#。我一开始以为它与 char 数组有关,但后来放入了一个 long,我完全糊涂了。

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

在我之前的一个问题中,我了解到我可以使用带有 EndianBinaryWriter 的 MemoryStream 来做一些简单的事情,比如

Memcpy(ScaleBuf, &VertScale, 4);

我在 MemoryStream 上创建 ScaleBuf 作为 Writer 并写出 VertScale。但是现在他们正在对实际缓冲区进行一些数学运算?我的 Ansi C 知识对我来说是阅读本文的基础。谁能给我解释一下他在这里做什么?

我猜他正在获取之前分配了一些内存的字符数组(如果它是一个)。然后将 Diff 的值放入其中。但是为什么要计算呢?计算数组中的偏移量?我在实际代码中简化了这个例子,memcpy 是 for 循环的一部分,每个循环 Diff 都有另一个值。为了保持内容的可读性和简明扼要,这里的示例有点太长了。

更新:根据提供的评论和答案,我设法在此处的 C++ 源代码下方添加了翻译。我不确定我是否遗漏了什么,并且还不完全知道如何在 C# 中进行单元测试,所以我首先需要阅读它以了解如何测试所有这些。如果有人看到我犯的错误,我会很高兴听到它,我希望这也能帮助其他人。

完整代码供引用

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;
}

我的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;
    }

最佳答案

基本上,它创建一个 char 数组,然后将 10 值(long 的前四个字节,无论它们是什么 - 这取决于字节顺序)复制到该 char 数组中的给定位置.

基本上,将 pointer + zi * 4 视为数组中的索引。如果 pDiffBuf 是一个字节数组,这与说 pDiffBuff[zi * 4] 是一样的。

我看不出这有什么用。你能再展示一些代码吗?

关于c# - 我无法使用 MemoryStream 将 C++ memcpy 代码转换为 C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22385326/

相关文章:

c# - 使用 foreach() 优化我的搜索功能 - 性能

c++ - 为什么要使用字符串的拷贝构造函数?

c++ - 编译错误: error C2704: __va_start intrinsic only allowed in varargs?的含义

c++动态数组初值

c++ - 这是使用 c_str 异常未定义行为吗?

c# - 从 ASP.NET Core 2.1 中的 MySqlConnector 获取查询日志

c# - "Could not create SSL/TLS secure channel"尝试从 Visual Studio 添加 Https 服务时出错

c# - MSUnit 测试异步 hell

c# - StackExchange NetGain 与 Node.js WS websocket 服务器性能

Java 内联 int 交换。为什么这只适用于 Java