Search code examples
cmemorymallocavr

changing dimensionality of allocated memory in c


Consider an array of framebuffers defined as follows:

static uint8_t framebuffer[num_buffers][1024];

The array was defined to have a single dimension per display buffer because the underlying hardware peripheral requires it in my embedded application. However, in other areas of the code, it would be highly advantageous to address the same framebuffers by additional dimensions, e.g.:

framebuffer[buf][page][col];

How do I accomplish this? Using real numbers, I would like the range of page to be 0 to 7 and col to be 0 to 127. Note: Each page is 128 bytes. For example, this statement would evaluate to true because they would be referencing the same byte:

framebuffer[0][130] == framebuffer[0][1][2]

because 130 / 128 = 1 (page) and 130 % 128 = 2 (column). I'm assuming I need to use malloc, but I've been unsuccessful at producing the correct behavior.


Solution

  • The "dimensionality" is not a property of the allocated memory, but the data type. You can access the same memory through a pointer of a different type with different dimensions provided you take care to ensure that the overall size and alignment are compatible. So for your example, you could do:

    static uint8_t framebuffer[numbuffers][1024];
    
    uint8_t (*redimensioned)[8][128] = (uint8_t (*)[8][128])framebuffer;
    

    ..and then, for example, zero the 4th column of the 3rd page of the 2nd buffer with:

    redimensioned[1][2][3] = 0;
    

    To elaborate a bit, the original declaration uint8_t framebuffer[numbuffers][1024]; declares an array of arrays (numbuffers arrays of 1024 uint8_t's). It would decay to a pointer to arrays of 1024 uint8_t's (or uint8_t (*)[1024], which can also be accessed as an N x 1024 2-dimensional array.

    We can also access that original array's contents through a pointer to arrays of 8 arrays of 128 uint8_t's, which is what uint8_t (*redimensioned)[8][128]; gives us, and which we can access as an N x 8 x 128 3-dimensional array (after pointing it at the original array's contents).

    To keep the compiler happy, when we point redimensioned at framebuffer's contents we have to cast it, since the types of the pointer framebuffer decays to is different from the type of the pointer we declared... which is where the (uint8_t (*)[8][128]) comes from in the assignment (it's a cast to "pointer to arrays of 8 arrays of 128 uint8_t's").