Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to create one function instead two functions of same purpose but different argument type? (Can I remove duplicate code?) [duplicate]

Tags:

c

Is it possible to create one function instead two functions of same purpose but different argument type?

I have two functions written in C, they convert image from RGB to HSV:

void png_rgb2hsv(pPNG_DATA data);
void jpg_rgb2hsv(pJPEG_DATA data);

they do exactly same thing: they take data->row_pointers and cycle it in a loop data->height times. Then it convert the values referred by data->row_pointers. This is how it works. But the only difference is that the data structures use different types. It seems to me senseless to use two functions for same thing. Especially when I would add more functions for more color spaces.

How this problem of program design is solved in practice in C?

Update: Most of readers didn't understand the question. I did not asked about overloading. It was question about design. I ask if is it possible to remove redundant function, "redundant" code. Because both functions are using same code, do the same thing, but the types in the function argument are different because one type is from libjpeg and the second type is from libpng. What I found is that it is not possible because it would mean use one variable for two different types.

like image 310
John Boe Avatar asked Feb 08 '15 10:02

John Boe


1 Answers

Use a generic macro:

void png_rgb2hsv(pPNG_DATA data);
void jpg_rgb2hsv(pJPEG_DATA data);

#define rgb2hsv(X) _Generic((X), pPNG_DATA: png_rgb2hsv, pJPEG_DATA: jpg_rgb2hsv)(X)

(If your compiler is too old and does not suport this trick (or you don't want to use it for some reason), then looks like there is no way to have 2 functions with same name and different argument type. Then, you would need to choose another solution.)

Update:

I misunderstood OP's question. If you want to create a single function for both types, you should do something like this:

void rgb2hsv_(Something *row_pointers, int height) // any member that you need goes here
{
    /* your code */
}

#define rgb2hsv(obj) \
do { \
_Generic((obj), pPNG_DATA: pPNG_DATA, pJPEG_DATA: pJPEG_DATA) tmp = (obj); \
    rgb2hsv_(tmp->row_pointers, tmp->height /*again, every member that you need should be stated here*/) \
} while (0)




Also, if pJPEG_DATA and pPNG_DATA have absolutely same internal layout (it means their members have same type and they are listed in the same order), you can try this: (it's not as safe as previous one, but at least it does not look like a bad hack)

void rgb2hsv(void *ptr)
{
    pPNG_DATA data = (pPNG_DATA *) ptr; // it does not matter which of 2 types you use here
    /* put your code that uses `data` here */
}

But keep in mind that if you swap 2 members in any of these structs or change their internal structure in any way, then this thing may no longer work.

( Also, you should know: these 2 techniques are just tricky workarounds to get a desired result. Best way is just to pass each needed member as separate argument and don't do this macro kung fu )

like image 164
HolyBlackCat Avatar answered Oct 03 '22 03:10

HolyBlackCat