0

This relates to C.

I am wondering if I can dynamically cast a pointer.

I have a struct called Value that encapsulates different data (for example, int and float arrays):

typedef struct {
    uint64_t count;  // array length
    int8_t   type;   // array type
    uint8_t  data[]; // array
} *Value;

ints have type = 1. floats have type = 2. (More types - including negative types - exist but are omitted in this example for simplicity.)

data[] can contain different types. The values are accessed by casting data, eg ((int *)x->data)[0].

Here is the code I use to add 2 Values:

#define ADD(x, y)  ((x) + (y))

#define APPLY_OP(op)                                  \
    if (1 == ret->type){                              \
        APPLY_OP_ACCESSORS(op, ((int *)ret->data));   \
    }                                                 \
    else {                                            \
        APPLY_OP_ACCESSORS(op, ((float *)ret->data)); \
    }


#define APPLY_OP_ACCESSORS(op, ra)
    if      (1 == x->type && 1 == y->type) { APPLY_OP_ITER(op, ra, ((int*  )x->data), ((int*  )y->data)) }  \
    else if (1 == x->type && 2 == y->type) { APPLY_OP_ITER(op, ra, ((int*  )x->data), ((float*)y->data)) }  \
    else if (2 == x->type && 1 == y->type) { APPLY_OP_ITER(op, ra, ((float*)x->data), ((int*  )y->data)) }  \
    else if (2 == x->type && 2 == y->type) { APPLY_OP_ITER(op, ra, ((floar*)x->data), ((float*)x->data)) }

#define APPLY_OP_ITER(op, ra, xa, ya) /* op, return/x/y accessors */     \
    if      (x->count == y->count) for (uint64_t i = 0; i < x->count; ++i) ra[i] = op( xa[i], ya[i] ); \
    else if (x->count  > y->count) for (uint64_t i = 0; i < x->count; ++i) ra[i] = op( xa[i], ya[0] ); \
    else {                         for (uint64_t i = 0; i < y->count; ++i) ra[i] = op( xa[0], ya[i] );}

Value add(Value x, Value y){

    // allocate an object for the return value
    Value ret = getReturnObject(x, y);

    // ...
    // handle if error
    // ...

    // calculate
    APPLY_OP(ADD);

    return ret;
}

The APPLY_OP macro has 2 branches, each having the same code except for the pointer type to the ret->data struct member. Is there some way i can avoid this branching/duplication, and dynamically change the ret->data pointer type instead? With more Value->types and more functions (subtract, multiply, divide, etc) the generated binary bloats up significantly.

NB this is simplified significantly from my own project. I omitted what I could. Hopefully the question is clear.

scrawl
  • 101
  • 1
  • 1
    Unrelated to your problem but defining a type-alias as a pointer tend to make code more confusing and harder to read and understand and maintain. Overuse of macros also leads to that. – Some programmer dude Feb 09 '22 at 19:20
  • 1
    You should probably be using a `union`, not type aliasing of pointers. – Barmar Feb 09 '22 at 19:22
  • You may get some insight from my answer here: https://stackoverflow.com/questions/65621027/writing-a-generic-struct-print-method-in-c/65621483#65621483 – Craig Estey Feb 09 '22 at 19:28
  • @Someprogrammerdude fair enough. i think macros are appropriate here, given they're used for multiple operations, and expanding them in multiple functions would lead to 100s of (repeated) LOC. factoring it out means i can update all functions simply by updating the macros. if there's a cleaner and more maintainable approach i'm all ears. – scrawl Feb 09 '22 at 19:29
  • @Barmar can a union be used with dynamic arrays? the advantage of this struct is that the object occupies contiguous memory. for context, i am writing an interpreter for an array language and this struct is how all data objects are represented – scrawl Feb 09 '22 at 19:36
  • @CraigEstey cheers, will take a look – scrawl Feb 09 '22 at 19:37
  • See one of my most highly voted answers: https://stackoverflow.com/questions/18577404/how-can-mixed-data-types-int-float-char-etc-be-stored-in-an-array/18577481#18577481 – Barmar Feb 09 '22 at 19:41
  • @Barmar thanks! will look – scrawl Feb 09 '22 at 19:45

0 Answers0