OiO.lk Blog C# How to use unions in C for pseudo-polymorphism
C#

How to use unions in C for pseudo-polymorphism


Consider a data structure to describe blocks of a matrix in C:

// Matrix block
typedef struct {
    union {
        int    i;
        double d;
    } *a;       // pointer to first element in matrix block
    int  k;     // block index
    int  p;     // no. of block rows
    int  q;     // no. of block columns
    int  m;     // no. of matrix rows
    int  n;     // no. of matrix columns
    int  r;     // MPI rank of block owner
} mtrx_blk;

I would like to use a union for the pointer to the first element of a matrix block. I would like to use the same mtrx_blk structure for different matrix types. In my case matrices can be either of type double or int. For example, if I create two matrix blocks with NBLK = 2; and a matrix A of type double:

// for each block
for (int k = 0; k < NBLK; k++) {

    blk[k] = (mtrx_blk) { .a = &A[k*P*Q], .k = k, .p = P, .q = Q, .m = M, .n = N, .r = k };
    }

Matrix A is of size M x N elements and matrix blocks are of size P x Q elements.

The above way to assign to a pointer .a results in an error:

gcc -std=c11 -pedantic-errors struct-union.c -o struct-union
struct-union.c: In function 'main':
struct-union.c:52:36: error: initialization of 'union <anonymous> *' from incompatible pointer type 'double *' [-Wincompatible-pointer-types]
   52 |         blk[k] = (mtrx_blk) { .a = &A[k*P*Q], .k = k, .p = P, .q = Q, .m = M, .n = N, .r = k };
      |                                    ^
struct-union.c:52:36: note: (near initialization for '(anonymous).a')

I tried to phrase it as:

// for each block
for (int k = 0; k < NBLK; k++) {

    blk[k] = (mtrx_blk) { .a.d = &A[k*P*Q], .k = k, .p = P, .q = Q, .m = M, .n = N, .r = k };
    }

But this also fails to compile with

gcc -std=c11 -pedantic-errors struct-union.c -o struct-union
struct-union.c: In function 'main':
struct-union.c:52:31: error: field name not in record or union initializer
   52 |         blk[k] = (mtrx_blk) { .a.d = &A[k*P*Q], .k = k, .p = P, .q = Q, .m = M, .n = N, .r = k };
      |                               ^
struct-union.c:52:31: note: (near initialization for '(anonymous)')
struct-union.c:52:38: error: initialization of 'union <anonymous> *' from incompatible pointer type 'double *' [-Wincompatible-pointer-types]
   52 |         blk[k] = (mtrx_blk) { .a.d = &A[k*P*Q], .k = k, .p = P, .q = Q, .m = M, .n = N, .r = k };
      |                                      ^
struct-union.c:52:38: note: (near initialization for '(anonymous).a')

My questions are:

  1. How do I do it correctly?
  2. Is my logic correct and can I use the analogous syntax .a.i = &B[k*P*Q] for a matrix B of an integer data type?

Please find the full source code below:

#include <stdlib.h>

// Matrix block
typedef struct {
    union {
        int    i;
        double d;
    } *a;       // pointer to first element in matrix block
    int  k;     // block index
    int  p;     // no. of block rows
    int  q;     // no. of block columns
    int  m;     // no. of matrix rows
    int  n;     // no. of matrix columns
    int  r;     // MPI rank of block owner
} mtrx_blk;

int main(int argc, char *argv[]) {

    // no. of matrix rows
    int const M = 10;

    // no. of matrix columns
    int const N = 10;

    // no. of blocks
    int const NBLK = 2;

    // no. of block rows
    int const P = M/NBLK;

    // no. of block columns
    int const Q = N;

    // allocate memory for matrix
    double *A = (double*) malloc(M*N*sizeof(double));

    // allocate array of blocks
    mtrx_blk *blk = (mtrx_blk*) malloc(NBLK*sizeof(mtrx_blk));

    // for each block
    for (int k = 0; k < NBLK; k++) {

        blk[k] = (mtrx_blk) { .a.d = &A[k*P*Q], .k = k, .p = P, .q = Q, .m = M, .n = N, .r = k };
    }

    // free memory of array of blocks
    free(blk);

    // free memory of matrix
    free(A);

    return 0;
}



You need to sign in to view this answers

Exit mobile version