C语言 将3D数组指针重构为2D

z9smfwbn  于 2023-04-11  发布在  其他
关注(0)|答案(1)|浏览(155)

我试图从一个3D数组中取出一个2D子数组,并将其传递给一个函数。原因是要像处理2D数组的数组一样处理这个3D数组中的数据。然而,数据应该像2D数组一样传递给函数。

pixelval_t subFrameData[MAX_SUBFRAMES][ARRAY_WIDTH][ARRAY_HEIGHT];

我使用了一些指针魔术,它工作正常,不显示警告。然而,在一个边缘情况下,它确实给予了[-Wstringop-overflow=]警告。
所以,有效的方法如下:

// function prototype
void SendImageBuffer_Subframe(pixelval_t dataarr[ARRAY_WIDTH][ARRAY_HEIGHT]);
...
// Some function somewhere
...
    for (int i = 0; i < MAX_SUBFRAMES; i++) {
        pixelval_t * ptr = &(subFrameData[i][0][0]); //get pointer of first element of 2D array
        SendImageBuffer_Subframe((pixelval_t (*)[ARRAY_HEIGHT]) ptr); //cast pointer and call function
    }
...

然而,如果我用固定索引而不是变量做同样的事情:

// function prototype
void SendImageBuffer_Subframe(pixelval_t dataarr[ARRAY_WIDTH][ARRAY_HEIGHT]);
...
// Some function somewhere
...
        pixelval_t * ptr = &(subFrameData[0][0][0]); //get pointer
        SendImageBuffer_Subframe((pixelval_t (*)[ARRAY_HEIGHT]) ptr); //cast pointer and call function
    }
...

它给了我以下警告:

main.c: In function ‘main’:
main.c:67:9: warning: ‘SendImageBuffer_Subframe’ accessing 48 bytes in a region of size 12 [-Wstringop-overflow=]
   67 |         SendImageBuffer_Subframe((pixelval_t (*)[ARRAY_HEIGHT]) ptr);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.c:67:9: note: referencing argument 1 of type ‘pixelval_t (*)[6]’ {aka ‘short int (*)[6]’}
main.c:35:6: note: in a call to function ‘SendImageBuffer_Subframe’
   35 | void SendImageBuffer_Subframe(pixelval_t dataarr[ARRAY_WIDTH][ARRAY_HEIGHT]){
      |      ^~~~~~~~~~~~~~~~~~~~~~~~

但是,代码确实可以工作,并且它给出了预期的输出。

在写这篇文章的时候,我发现下面的代码可以正常工作,没有错误

const int defaultIndex = 0;
        pixelval_t * ptr = &(subFrameData[defaultIndex][0][0]);
        SendImageBuffer_Subframe((pixelval_t (*)[ARRAY_HEIGHT]) ptr);

我猜结果会完全一样。这只是一个编译器的怪癖,还是有一个合适的解释?或者我只是完全走错了路,重新铸造指针?
注意:我知道我可以通过直接处理数组指针来避免所有这些。2但是我发现数组的语法糖很好地保持了代码的可理解性。

cgvd09ve

cgvd09ve1#

或者我只是完全在错误的轨道上与重铸指针?
是的。
原因是操纵该3D阵列中的数据,就好像它是2D阵列的阵列一样。
它 * 是 * 一个2D数组的数组。这正是C中多维数组的工作方式。my_3D_array[i]给你一个2D数组。不需要强制转换任何东西。
所以你的函数应该是:

for (int i = 0; i < MAX_SUBFRAMES; i++) {
    SendImageBuffer_Subframe(subFrameData[i]); 
}

至于为什么(pixelval_t (*)[ARRAY_HEIGHT])转换有效,这只是因为在那个内存位置上碰巧有一个1D数组。一个2D数组。一个3D数组。和一个单一的项目。它们都从同一个地址开始。
任何带有数组的C函数都会将它们静默地调整为指向该数组第一个元素的指针。在pixelval_t dataarr[ARRAY_WIDTH][ARRAY_HEIGHT]的情况下,第一个元素的类型是pixelval_t [ARRAY_HEIGHT],指向该类型的指针是pixelval_t (*) [ARRAY_HEIGHT]。因此,强制转换不会导致任何编译器消息,因为:

void SendImageBuffer_Subframe(pixelval_t dataarr[ARRAY_WIDTH][ARRAY_HEIGHT]);

100%等同于:

void SendImageBuffer_Subframe(pixelval_t (*dataarr)[ARRAY_HEIGHT]);

相关问题