I am trying to take a 2D sub array from a 3D array, and pass it to a function. The reason is to manipulate data in this 3D array as if it were an array of 2D arrays. However the data should be passed to the functions as if they were 2D arrays.
pixelval_t subFrameData[MAX_SUBFRAMES][ARRAY_WIDTH][ARRAY_HEIGHT];
I have worked some pointer magic, and it works, and does not show warnings. However, in one edge case it does give a [-Wstringop-overflow=] warning.
So what works is the following:
// 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
}
...
However, if I do the same with a fixed index instead of a variable:
// 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
}
...
It gives me the following warning:
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]){
| ^~~~~~~~~~~~~~~~~~~~~~~~
However, the code does work, and it gives the expected output.
While writing this up, I found that the following does work, without errors
const int defaultIndex = 0;
pixelval_t * ptr = &(subFrameData[defaultIndex][0][0]);
SendImageBuffer_Subframe((pixelval_t (*)[ARRAY_HEIGHT]) ptr);
Which would result in exactly the same, I would guess. Is this just a compiler quirk, or is there a proper explanation for why that is? Or am I just completely on the wrong track with recasting the pointers?
note: I am aware that I could avoid all of this by just working directly on the array pointer. But I find the syntactic sugar of that arrays is nice to keep the code understandable.
Or am I just completely on the wrong track with recasting the pointers?
Yes.
The reason is to manipulate data in this 3D array as if it were an array of 2D arrays.
It is an array of 2D arrays. That's exactly how multi-dimensional arrays in C work. my_3D_array[i]
gives you a 2D array. No need to cast anything.
So your function should be:
for (int i = 0; i < MAX_SUBFRAMES; i++) {
SendImageBuffer_Subframe(subFrameData[i]);
}
As for why the (pixelval_t (*)[ARRAY_HEIGHT])
cast works, it is just because there happens to be a 1D array on that memory location. And a 2D array. And a 3D array. And a single item. They all start on the same address.
Any C function with arrays will get them silently adjusted to a pointer to the first element of that array. In case of pixelval_t dataarr[ARRAY_WIDTH][ARRAY_HEIGHT]
the first item is of type pixelval_t [ARRAY_HEIGHT]
and a pointer to such is pixelval_t (*) [ARRAY_HEIGHT]
. Therefore the cast doesn't lead to any compiler messages, since:
void SendImageBuffer_Subframe(pixelval_t dataarr[ARRAY_WIDTH][ARRAY_HEIGHT]);
is 100% equivalent to:
void SendImageBuffer_Subframe(pixelval_t (*dataarr)[ARRAY_HEIGHT]);