开发者

Is there a way to get template effect in C?

开发者 https://www.devze.com 2023-03-15 08:19 出处:网络
I\'ve developed a C dll containing simple link list functions but they all are defined on int type i.e. when ever the user will create a link list using my li开发者_运维百科brary he can only created a

I've developed a C dll containing simple link list functions but they all are defined on int type i.e. when ever the user will create a link list using my li开发者_运维百科brary he can only created a list of ints.So what if I could do something(except void*) to let the user create a list of arbitrary data types say char,float or even user define struct?That too without recompilation.

thanks.


Using macros is a decent approach to templatizing definitions, i.e. generating any number of definitions based on a pattern. Here is an example -- but it is ugly as hell.

#include <stdlib.h>

#define template_struct_A(T1,T2) struct A_ ## T1 ## _ ## T2 { \
    T1 a; \
    T2 b; \
}
#define struct_A(T1,T2) struct A_ ## T1 ## _ ## T2

struct C { const char*s; };

typedef const char* pchar;
template_struct_A(int, pchar); // explicit instantiation of struct A<int, pchar>

int main() {
    struct X { struct C x; } x;
    struct_A(int, pchar) o1; // struct A<int, const char*> o1
    o1.a = 1;
    o1.b = "hello";

    struct_A(int, pchar) o2; // struct A<int, const char*> o2
    o2.a = o1.a * 2;
    o2.b = "world";

    typedef struct_A(int, pchar)* pAInt;
    typedef struct C structC;
    template_struct_A(pAInt, structC) o3; // struct A<struct A<int, const char*>, struct C> o3
    o3.a = &o2;
    o3.b.s =  "hi";

    printf ("o1.a = %d, o1.b = %s, o2.a = %d, o2.b = %s, o3.b.s = %s\n", o1.a, o1.b, o2.a, o2.b, o3.b.s);
}


The only option, apart from void * is, well, nothing.

The only option is void *, is what I'm saying.

void * is the only generic type in C; and to a degree, also the only generic degree in C++; as neither are what you would call dynamic languages.

Of course, if you were feeling particularly crazy, you could readjust your internal struct for linked list links to include a union, and have a series of functions named as

add_<type>_to_list(); // <type> = char, int, float…

But that's not likely to give satisfactory results.


Language/Compiler Support

  • typeof
  • _Generic (and Clang)

Examples

  • Type safe binary search
  • MIN/MAX


I agree with the other answers that void * is the only way to go. But you can squeeze more dynamic behavior without recompiling if you add a size parameter that indicates how many bytes the void * points to.

void *shift(list *plist, unsigned size);
void unshift(list *plist, void *item, unsigned size);

Then you can hide the size with macros.

#define Cshift(L)   shift(L,sizeof(char))
#define Cunshift(L,I) unshift(L,I,sizeof(char))


There is no way to do it at runtime without void *. But there is way to do it without separately compiled code: all operations can be #define.

http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/sys/queue.h?rev=1.75;content-type=text%2Fx-cvsweb-markup


You could use macros. For example you can make different list node types, with differently typed data members and keep sure all have a next and prev member. Then just use macros for all the list operations (like add, insert, remove), as these don't care about the type stored.

Of course macros aren't that type safe as templates and are considered "bad style". But hey we're in C, who fears macros in C? And void* isn't that type safe, too.


You could essentially rewrite C++ in C, to whichever level of detail you need. You could start with making the linked list's data type a struct * to some wrapper structure which itself could contain a type identifier and a void pointer to the actual data. You could write your own vtable to allow for polymorphism, and you could add reference counting and memory management... none of that is magic, so if you really need that sort of generality, you could certainly write it all in C. Or just use C++ :-)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号