开发者

Which way is better for creating type-agnostic structures in C?

I'm trying to write some generic structures. Essentially, what I need for my purpose is C++ templates, but since I'm writing in C, templates are out of consideration. Currently I'm considering 2 ways of achieving what I want.

Method 1: use the preprocessor. Li开发者_Go百科ke so:

#define DEFINE_PAIR(T) typedef struct Pair_##T{ \
                           T x; \
                           T y; \
                        } Pair_##T

DEFINE_PAIR(int);

int main(){
   Pair_int p;
   return 0;
}

An obvious downside to it is that you have to invoke the macro before using the type. Probably there are more disadvantages, which I hope you will point out.

Method 2: just use void-pointers, like so:

typedef struct Pair{
   void* x;
   void* y;
} Pair;

Obviously, this approach is not type safe (I could easily pass a pair of strings to a function expecting a pair of doubles), plus the code doing deallocation gets a lot messier with this approach.

I would like to hear your thoughts on this. Which of the two methods is better/worse and why? Is there any other method I could use to write generic structures in C?

Thanks.


If you only plan on using primitive data types, then your original macro-based solution seems nifty enough. However, when you start storing pairs of pointers to opaque data types with complex structures underneath that are meant to be used by passing pointers between functions, such as:

complex_structure_type *object = complex_structure_type_init();
complex_structure_type_set_title(object, "Whatever");
complex_structure_type_free(object);

then you have to

typedef complex_structure_type *complex_structure_type_ptr; 

in order to

DEFINE_PAIR(complex_structure_type_ptr);

so you can

Pair_complex_structure_type_ptr p;

and then

p.x = object;

But that's only a little bit more work, so if you feel it works for you, go for it. You might even put together your own preprocessor that goes through the code, pulls out anything like Pair_whatever, and then adds DEFINE_PAIR(whatever) for the C preprocessor. Anyway, it's definitely a neat idea that you've presented here.

Personally, I would just use void pointers and forget about strong type safety. C just doesn't have the same type safety machinery as other languages, and the more opportunities you give yourself to forget something, the more bugs you'll accidentally create.

Good luck!


Noting that templates in c++ provide a language for writing code, you might simple consider doing code generation with some tool more powerful than the c-preprocessor.

Now that does add another step to you build, and makes you build depend on another toll (unless you care to write your own generator in c...), but it may provide the flexibility and type-safety you desire.


This is almost the same, but it's a bit more nimble:

#define PAIR_T(TYPE) \
    struct { \
        TYPE x; \
        TYPE y; \
    }


typedef PAIR_T(int) int_pair;
typedef PAIR_T(const char *) string_pair;

int main(void)
{
    int_pair p = {1, 1};
    string_pair sp = {"a", "b"};
}
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜