我正在尝试将 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/