2

I'm trying to simulate the "template" style behavior in C as part of an exercise to refactor code from cpp to C. I constructed a MACRO approach by defining as struct like so:

#define FIFO(TYPE, depth, NAME)                                     \
     typedef struct fifo_##TYPE##NAME                               \
     {                                                              \
        TYPE array[depth];                                          \
        uint8 st_idx;                                               \
        uint8 end_idx;                                              \
        uint32 cnt;                                               \
     }fifo_##TYPE##NAME;                                            \
     void fifo_##TYPE##NAME_init(fifo_##TYPE##NAME *f);             \
     int fifo_##TYPE##NAME_push(fifo_##TYPE##NAME *f, TYPE *elem);  \
     TYPE* fifo_##TYPE##NAME_pop(fifo_##TYPE##NAME *f);             \
     TYPE* fifo_##TYPE##NAME_peek(fifo_##TYPE##NAME *f);            \

I then defined MACRO functions for the prototypes shown above. This actually increased my code size as compared to template approach, since each of the functions were being defined for every TYPE.

I'm now attempting a void* approach instead of MACRO. I'm still using the MACRO struct definition as above, but I'm not defining MACRO functions. I'm using ordinary inline functions in the .h file but I'm stuck on how to access the members of the generic TYPE struct through a void* ptr. What type can I cast it to? If the name of the struct changes as per TYPE, I don't have a definite struct type to cast it to. Also, MACROs wouldn't work in non-macro functions.

Sorry for the verbiage! Thanks.

a3f
  • 8,517
  • 1
  • 41
  • 46
thegeeklife
  • 107
  • 6
  • I think it is not a big problem that the code size increases. You will have type safety, which you will not have using your void* approach. – wimh Mar 13 '15 at 20:36
  • void* can be casted to any other pointer type. So your generic functions should work with pointers rather than structures. – Eugene Sh. Mar 13 '15 at 20:38
  • @Wimmel Thanks for the response. Could you please elaborate on that if you don't mind? Would help me getting a clearer idea. Thanks! – thegeeklife Mar 13 '15 at 20:39
  • @thegeeklife memory is cheap. storage is cheap. fixing bugs is expensive. Unless you are developing for an embedded environment with limited resources, I think you should not care much about code size. Readability of your code is much more important, so it will be easier to maintain for you and others. Note that I also not really like the big `#define`, I would rather solve this using code generation. The generated code can be easier debugged. – wimh Mar 13 '15 at 20:45
  • I would be accessing the members of that struct in the generic functions, so I guess I would need to cast it to that particular struct type right ? Also, the call to these functions would pass the address of the struct which would be collected in a void* .. – thegeeklife Mar 13 '15 at 20:48
  • @Wimmel I agree with you about the ugliness of the large macro, although that's what I could come up with in C. And yes I am optimizing for code size constraints. If nothing else, I would probably fall back to cpp – thegeeklife Mar 13 '15 at 21:03
  • 1
    Consider putting the array last. See 6.5.2.3 Structure and union members: _One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (...) for a sequence of one or more initial members._ – Jonathan Leffler Mar 13 '15 at 21:04
  • 1
    Can you give a code example of what you're trying to do? (I.e. some code that doesn't work that you want to work) – user253751 Mar 13 '15 at 21:16
  • Why do you need `NAME`? If you're going a C++ templates sort of thing, then you'd know that `FIFO` would be like `FIFO(int, 10)`. What use does `NAME` have when defining such a type (does `FIFO_intX` with a depth of 10 differ in structure from `FIFO_intY` with a depth of 10?) Does the [Type-safe generic containers with macros](http://stackoverflow.com/questions/9401975/type-safe-generic-containers-with-macros?rq=1) topic help at all? –  Mar 13 '15 at 23:06
  • Also, is `array` resizable? If it is, then it doesn't make sense to have a `depth` parameter to me at all when you can just allocate using a default size, similar to the default constructor in C++, and you can provide another function to allocate a specific amount for `depth` as with a constructor accepting a `depth` argument. I apologize for all of the questions, but the more I look at this, the more it seems like it tries to achieve more than just C++ templates. I don't understand the reason behind the particular design of the macro, I guess. –  Mar 13 '15 at 23:12
  • @Chrono Kitsune Yes array is resizeable according to the type. I did refer the link u provided. Thanks! But my primary issue here is still in accessing members of the struct through non-macro functions – thegeeklife Mar 13 '15 at 23:58
  • Trying to do this: `inline void init(void* f) { f->count=0; //f needs to be type cast into the struct type f->end_idx =0; f->st_idx =0; } ` The calling function is like: `init(&fifo1); ` – thegeeklife Mar 14 '15 at 00:51
  • I think you'd need to cast to a generic type and use generic functions, not the other way around. I just finished implementing that. It's not pretty, but it does seem to work (I haven't found any bugs yet anyway.) You can [view it all in one source file](http://pastebin.com/h26LnyLM). Fair warning: it's long. I hope you can grok the byte-level pointer arithmetic. `int16_t *p = (void*)0; p += 2;` and `unsigned char *p = (void *)0; p += 2 * sizeof(int16_t);` both result in `p==(void*)8` being true. I just use it a lot is all. –  Mar 14 '15 at 05:29

0 Answers0