如何将简单指针转换为固定大小的多维数组?

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/gytw7 float * 不可能指向多维 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];,据我所知,无法保证&amp;arr[0][1] + 1&amp;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 也许你的编译器坏了?如果您可以提供您遇到问题的完整代码,那么值得提出一个单独的问题。 为什么会这样?是否有关于此演员表以及混合指针和数组表示法的类型的明确文档?谢谢

以上是关于如何将简单指针转换为固定大小的多维数组?的主要内容,如果未能解决你的问题,请参考以下文章

PHP:将多维数组转换为简单数组

动态大小的多维数组的 C++ 解决方法

如何将多维数组转换为json对象[关闭]

将多维数组转换为一维数组的算法

如何将多维数组转换为Laravel中的集合

如何将多维PHP数组转换为html表