如何将简单指针转换为固定大小的多维数组?
Posted
技术标签:
【中文标题】如何将简单指针转换为固定大小的多维数组?【英文标题】:How to cast simple pointer to a multidimensional-array of fixed size? 【发布时间】:2012-08-05 19:56:33 【问题描述】:我有一个函数,它接受一个指向浮点数组的指针。基于其他条件,我知道指针实际上指向一个 2x2 OR 3x3 矩阵。 (实际上内存最初是这样分配的,例如 float M[2][2] )重要的是我想在函数体中做出这个决定,而不是作为函数参数。
void calcMatrix( int face, float * matrixReturnAsArray )
// Here, I would much rather work in natural matrix notation
if( is2x2 )
// ### cast matrixReturnAsArray to somethingAsMatrix[2][2]
somethingAsMatrix[0][1] = 2.002;
// etc..
else if(is3x3)
//etc...
我知道我可以使用模板和其他技术来更好地解决这个问题。我的问题实际上是关于如何在### 评论中制作这样的演员表。使用 C++ 工作。
【问题讨论】:
我认为您正在尝试解决错误的问题(即“如何投射?”很少是正确的问题)。对于“如何轻松使用多维数组”的问题,我写了一个简单的解决方案。一次:ideone.com/gytw7float *
不可能指向多维 anything (除非您不应该进行非常糟糕的转换,如果编译器让你)。 float *
指向一个浮点数,它可能是一维浮点数数组中的第一个值。但它并不指向任何子数组,因为您需要一个多维数组。 2x2 和 3x3 都是 2D,所以两者都可以是 float **
。但实际上,创建(或查找)并使用专用的 Matrix
类会更好。
好的,我可以将输入参数更改为 float **。但是你是说在float aMDarray[3][3]的情况下,不保证元素的存储是连续的吗?
@DragonWraith:对不起,你错了。 float a[2][2];
与 float**
不兼容。
@DragonWraith:不过,这仍然是错误的。 float a[2][2];
仍然是一个连续存储的 float
的单个序列,但使用编译器提供的二维地址计算。然后你可以写float* p = &a[0][0];
自己做指数计算。
【参考方案1】:
float *
可以指向浮点数组的第一个元素,并且应该重新解释为该数组类型。并且该转换的结果可能指向 float [][]
的第一个元素,因此应该 reinterpret_castable 到该类型,依此类推。你应该能够组成这样的演员表,直接做
float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(matrixReturnAsArray);
float **
类型的参数不相同,不应以这种方式使用。
为避免未定义行为,指针必须源自实际的多维数组,如果直接使用float*
,则只能访问多维矩阵的第一行。
void foo(float *f)
f[3] = 10.;
float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(f);
arr[1][1] = 10.;
void main()
float a[2][2];
foo(&a[0][0]); // f[3] = 10.; is undefined behavior, arr[1][1] = 10. is well defined
float b[4];
foo(&b[0]); // f[3] = 10.; is well-defined behavior, arr[1][1] = 10. is undefined
鉴于float arr[2][2];
,据我所知,无法保证&arr[0][1] + 1
与&arr[1][0]
相同。因此,尽管您可以通过 f[i*width + j]
将单维数组用作多维数组,但您不能将多维数组视为单维数组。
最好使用 C++ 的编译时类型安全,而不是仅仅依靠不意外地传递错误的东西或执行错误的 reinterpret_cast。要使用原始数组获得类型安全,您应该使用对所需原始数组类型的引用:
void foo(float (&f)[2][2])
void foo(float (&f)[3][3])
如果您想按值传递数组,则不能使用原始数组,而应使用 std::array: 之类的东西:
void foo(std::array<std::array<float,2>,2> f)
void foo(std::array<std::array<float,3>,3> f)
【讨论】:
不保证sizeof (T [N])
完全是N * sizeof (T)
?
我知道标准中有一个非规范性的注释提到了这一点。如果您能找到任何规范的内容,请告诉我。
5.3.3p2 直接声明是必需的。对我来说看起来很规范(不在“注释”内)
“当应用于数组时,结果是数组中的总字节数。这意味着包含 n 个元素的数组的大小是元素大小的 n 倍。”问题是我没有看到任何实际上禁止数组最后包含额外空间的东西。据说是“暗示”的,但我不明白。
如果没有别的,该行禁止在数组末尾填充,因为该行是规范的。【参考方案2】:
明智地使用 typedef,这种类型的转换总是更干净,更容易处理:
typedef float Matrix_t[2][2];
Matrix_t* someThingAsMatrix = (Matrix_t*) matrixReturnAsArray;
如果这是 C++ 而不是 C,那么您应该创建一个矩阵类。 (或者更好的是,寻找一个开源的。)
【讨论】:
使用 someThingAsMatrix[1][1] = 2.0f;给出:将“float”分配给“float [2]”时的类型不兼容 Typedef 仍然有帮助,但您需要:typedef float MatrixRow[2]; MatrixRow* someThingAsMatrix = (MatrixRow*) matrixReturnAsArray;
相当于 ecatmur 的答案。【参考方案3】:
float (*somethingAsMatrix)[2] = (float (*)[2]) matrixReturnAsArray;
【讨论】:
谢谢。这现在肯定有效。我只是澄清一下我是否对声明案例中保证的元素连续排列有误解 float aMDarray[3][3]; @NoahR:这是连续的,并且与您建议的用法兼容。 我尝试了这种技术,Mac OS X C++ 编译器说error: assigning to 'double (*)[LDN]' from incompatible type 'double (*)[LDN]'
。请注意,两种报告的类型是相同的!那么为什么它们不可分配呢?我的代码看起来像这样double (*F)[LDN]; F=(double (*)[LDN])AF;
我也尝试在声明中初始化并得到类似的错误消息。
@Jason 也许你的编译器坏了?如果您可以提供您遇到问题的完整代码,那么值得提出一个单独的问题。
为什么会这样?是否有关于此演员表以及混合指针和数组表示法的类型的明确文档?谢谢以上是关于如何将简单指针转换为固定大小的多维数组?的主要内容,如果未能解决你的问题,请参考以下文章