对在 C# 中从 IntPtr 访问元素感到困惑
Confused about accessing elements from IntPtr in C#
我正在使用包含以下 CameraSpacePoint 结构的 Kinect v2:
public struct CameraSpacePoint : IEquatable<CameraSpacePoint>
{
public float X;
public float Y;
public float Z;
}
CameraSpacePoint
还包含一些方法 Equals
、GetHashCode
等,上面没有显示这些方法以保持 post 简洁。
嗯,我在class构造函数中定义cameraSpacePoints
如下:
IntPtr cameraSpacePoints = Marshal.AllocHGlobal(512 * 424 * 4 * 3);
下面是上面内存分配的解释:
- 512: 宽度
- 424: 身高
- 4:单个 'float'
所需的字节数
- 3:总共三个变量,即 'X'、'Y' 和 'Z'
后来,我使用 CoordinateMapper 将值复制到 cameraSpacePoints,如下所示:
coordinateMapper.MapDepthFrameToCameraSpaceUsingIntPtr(depthFrameData,
512 * 424 * 2,
cameraSpacePoints,
512 * 424 * 4 * 3);
看起来很完美。现在我想从 cameraSpacePoints 获取值。所以我在 unsafe
块中使用了以下代码:
float* cameraSpacePoint = (float*)cameraSpacePoints;
for (var index = 0; index < 512 * 424; index++)
{
float X = cameraSpacePoint[index];
float Y = cameraSpacePoint[index + 1];
float Z = cameraSpacePoint[index + 2];
}
我在想象它时意识到它似乎不起作用。在我看来,使用 IntPtr
从 cameraSapacePoints 访问元素时存在一些混淆。这里缺少什么?有什么建议吗?
在您的初始代码中,您将 IntPtr
(指向 CameraSpacePoint
的数组[])转换为原始浮点指针。如果您将 IntPtr
解释为原始 float
s,因为您一次处理 3 个点(x、y 和 z),您需要每次将循环递增 3 个浮点数,例如(为清楚起见,我重命名了变量):
var floats = (float*)cameraSpacePoints;
for (var index = 0; index < 512 * 424; index+=3)
{
var x = floats[index];
var y = floats[index + 1];
var z = floats[index + 2];
var myCameraSpacePoint = new CameraSpacePoint
{
X = x,
Y = y,
Z = z
};
// use myCameraSpacePoint here
}
但这是处理数据的一种非常低效的方式,因为无论如何数据最初都是 CameraSpacePoint
。更好的方法是将结构直接转换回实际类型:
var cameraSpacePoints = (CameraSpacePoint*)cameraSpacePoints;
for (var index = 0; index < 512 * 424; index++)
{
var cameraSpacePoint = cameraSpacePoints[index];
// Do something with cameraSpacePoint
}
通过转换为正确的类型 (CameraSpacePoint
),我们还提高了代码的健壮性 - 例如如果将来向 CameraSpacePoint
的新版本添加其他字段,那么针对新版本重新编译代码将再次起作用,而直接访问 float
会破坏封装并使维护困难。
我们不再需要将循环递增 3 的原因是,当我们在 cameraSpacePoints[index]
上使用下标/索引操作时,编译器知道在偏移量 n * sizeof(CameraSpacePoint)
的位置在初始cameraSpacePoints[0]
之后。 sizeof(CameraSpacePoint)
是 3 个浮点数的大小。
我正在使用包含以下 CameraSpacePoint 结构的 Kinect v2:
public struct CameraSpacePoint : IEquatable<CameraSpacePoint>
{
public float X;
public float Y;
public float Z;
}
CameraSpacePoint
还包含一些方法 Equals
、GetHashCode
等,上面没有显示这些方法以保持 post 简洁。
嗯,我在class构造函数中定义cameraSpacePoints
如下:
IntPtr cameraSpacePoints = Marshal.AllocHGlobal(512 * 424 * 4 * 3);
下面是上面内存分配的解释:
- 512: 宽度
- 424: 身高
- 4:单个 'float' 所需的字节数
- 3:总共三个变量,即 'X'、'Y' 和 'Z'
后来,我使用 CoordinateMapper 将值复制到 cameraSpacePoints,如下所示:
coordinateMapper.MapDepthFrameToCameraSpaceUsingIntPtr(depthFrameData,
512 * 424 * 2,
cameraSpacePoints,
512 * 424 * 4 * 3);
看起来很完美。现在我想从 cameraSpacePoints 获取值。所以我在 unsafe
块中使用了以下代码:
float* cameraSpacePoint = (float*)cameraSpacePoints;
for (var index = 0; index < 512 * 424; index++)
{
float X = cameraSpacePoint[index];
float Y = cameraSpacePoint[index + 1];
float Z = cameraSpacePoint[index + 2];
}
我在想象它时意识到它似乎不起作用。在我看来,使用 IntPtr
从 cameraSapacePoints 访问元素时存在一些混淆。这里缺少什么?有什么建议吗?
在您的初始代码中,您将 IntPtr
(指向 CameraSpacePoint
的数组[])转换为原始浮点指针。如果您将 IntPtr
解释为原始 float
s,因为您一次处理 3 个点(x、y 和 z),您需要每次将循环递增 3 个浮点数,例如(为清楚起见,我重命名了变量):
var floats = (float*)cameraSpacePoints;
for (var index = 0; index < 512 * 424; index+=3)
{
var x = floats[index];
var y = floats[index + 1];
var z = floats[index + 2];
var myCameraSpacePoint = new CameraSpacePoint
{
X = x,
Y = y,
Z = z
};
// use myCameraSpacePoint here
}
但这是处理数据的一种非常低效的方式,因为无论如何数据最初都是 CameraSpacePoint
。更好的方法是将结构直接转换回实际类型:
var cameraSpacePoints = (CameraSpacePoint*)cameraSpacePoints;
for (var index = 0; index < 512 * 424; index++)
{
var cameraSpacePoint = cameraSpacePoints[index];
// Do something with cameraSpacePoint
}
通过转换为正确的类型 (CameraSpacePoint
),我们还提高了代码的健壮性 - 例如如果将来向 CameraSpacePoint
的新版本添加其他字段,那么针对新版本重新编译代码将再次起作用,而直接访问 float
会破坏封装并使维护困难。
我们不再需要将循环递增 3 的原因是,当我们在 cameraSpacePoints[index]
上使用下标/索引操作时,编译器知道在偏移量 n * sizeof(CameraSpacePoint)
的位置在初始cameraSpacePoints[0]
之后。 sizeof(CameraSpacePoint)
是 3 个浮点数的大小。