struct ListNode_ {
 struct ListNode_* prev;
 struct ListNode_* next;
 char value[1]; /* 可変長 */
};

として、リストの関数内ではこれで扱ってるフリをし、
外では

struct ListNodeInt {
 struct ListNodeInt* prev;
 struct ListNodeInt* next;
 int value;
};

とかを使うってのもできないこともない。
ただ、色々と型チェックできないのが欠点。
俺は、多少気持悪くても、テンプレート紛いのマクロの方が好きかな。