سؤال

I am writing a basic library for low level image processing in C. I am aware that other (very good) libraries exist; this is a learning experience for me, not a means to an end.

I have defined the following (simplified, for this question) constructs:

union img_rawdata{
    uint8_t*  u8;
    uint16_t* u16;
    float*    flt;
};

enum img_type{
    IMG_U8,
    IMG_U16,
    IMG_FLT
};

struct image{
    union img_rawdata  rawdata;
    enum img_type      type;
    unsigned int       num_values;
};

My question is this: What is the favored way to dynamically allocate the proper pointer within the union?

Right now, the only way I see is to use a switch statement, like:

void alloc_img(struct image* img, enum img_type type, unsigned int num_vals){
    switch (type){
        case IMG_U8:
            img->rawdata.u8 = (uint8_t*)malloc(num_vals*sizeof(uint8_t));
        break;            
        case IMG_U16:
            img->rawdata.u16 = (uint16_t*)malloc(num_vals*sizeof(uint16_t));
        break;
        case IMG_FLT:
            img->rawdata.flt = (float*)malloc(num_vals*sizeof(float));
        break;
    }
}

This doesn't seem so bad; however, in my implementation, the actual memory allocation is about 50 lines (as rawdata is not one dimensional, error checking, etc.).

Is there any preprocessor magic that can reduce code redundancy, or is this the best way to go about writing this?

Or, alternatively, is there a different way altogether to approach the problem that will avoid this issue entirely?

هل كانت مفيدة؟

المحلول

[assuming all types of pointers including void * have the same size]

Modify what you have like so

union img_rawdata {
  void * untyped;
  uint8_t * u8;
  uint16_t * u16;
  float * flt;
};

enum img_type {
  IMG_UNDEF = -1
  IMG_U8 = 0,
  IMG_U16,
  IMG_FLT,
  IMG_MAX
};

and add

const size_t img_type_size[IMG_MAX] = {
  sizeof(*((union img_rawdata *) NULL)->u8),
  sizeof(*((union img_rawdata *) NULL)->u16),
  sizeof(*((union img_rawdata *) NULL)->flt)
};

then replace the switch by:

assert(IMG_UNDEF < type && IMG_MAX > type);
img->rawdata.untyped = malloc(num_vals * img_type_size[type]);

نصائح أخرى

void alloc_img(struct image * img, enum img_type type, unsigned int num_vals){
    size_t basesize = 0;
    switch (type){
        case IMG_U8:
            basesize = sizeof(uint8_t);
        break;            
        case IMG_U16:
            basesize = sizeof(uint16_t);
        break;
        case IMG_FLT:
            basesize = sizeof(float);
        break;
    }
    if (basesize) {
        img->rawdata.u8 = malloc(num_vals * basesize);
        // assigning to u8 is the same as assigning to any other member
        // but it may be better to use a void* as in
        // img->rawdata.voidptr = malloc(num_vals * basesize);
    } else {
        fprintf(stderr, "default missing in switch\n");
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top