Question

I have a one-dimensional array int *data and I know the number of rows and cols which are effectively stored within it. That is, I can access an element of the two-dimensional matrix (i,j) by using something like data[i*cols+j].

Specifically, these are stored in a struct:

typedef struct {
    int *data;
    int rows;
    int cols;
} matrix_t;

At some point in the past, I also wrote this voodoo code:

#define MATRIXP(m) __typeof__(__typeof__(__typeof__(*((m).data))[(m).cols]) *)
#define MATRIXD(m) ((MATRIXP(m)) ((m).data))

With these definitions, I am able to do:

MATRIXP(matrix) m = MATRIXD(matrix);

And then I can use the matrix m as a two-dimensional matrix pointer for accessing data.

m[3][2] = 5; /* assign the element in row 3 and column 2 */

This is very nice and means I don't need to remember to always have an expression like data[i*cols+j]. However, I wrote this code some time ago and I now cannot remember how it works.

  1. Can someone please explain exactly how all those __typeof__ operators are working, and how to go about reading similar expressions? What is the type of the variable m?

    I know it expands to something like:

    __typeof__(__typeof__(__typeof__(*((matrix).data))[(matrix).cols]) *) m = ((__typeof__(__typeof__(__typeof__(*((matrix).data))[(matrix).cols]) *)) ((matrix).data));
    
  2. Is this method of accessing data safe? Is it the best way to do this?

Was it helpful?

Solution

Question 1:

MATRIXP(matrix) m (matrix should be a variable of type matrix_t) will be expanded to

__typeof__(__typeof__(__typeof__(*((matrix).data))[(matrix).cols]) *) m

From in side to out side

  1. __typeof__(*((matrix).data)) is the type of *((matrix).data), which is int according to the definition of matrix_t.

  2. so (__typeof__(*((matrix).data))[(matrix).cols]) equals (int [cols])

  3. so __typeof__(__typeof__(*((matrix).data))[(matrix).cols]) *) equals (int [cols] *)

  4. and that is the type given by MATRIXP(matrix).

Therefore, MATRIXP(matrix) equals (int [(matrix).cols] *). In other words,

MATRIXP(matrix) m

is effectively

int (*m)[matrix.cols]

As pointed out by @codebeard

Question 2:

It looks quite safe to me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top