在 C 语言中写类型安全的泛型容器
https://danielchasehooper.com/posts/typechecked-generic-c-data-structures/
比较可惜的是,在看到这篇博客之前,我已经写完了这学期数据结构的 oj 代码了
众所周知,用 C 写非侵入式泛型容器是很坐牢的事,要么全用 void*
一顿擦除,性能不高的同时还容易写错类型,要么写一个全是 define
的头文件,根据需要什么类型就 #define T int
然后 include
一下,产生很多重复代码,而且全 define
很难 debug 或代码提示。
这篇博客给出了一个令人耳目一新的方法
效果是这样的:
1 | typedef struct { |
定义容器时只需要在括号里加上类型参数,然后就获得了编译期类型检查,完全不影响运行时性能。
容器算法用的是同一个函数,不需要 list_prepend_int
和 list_prepend_foo
等等。
原理:
首先用一个柔性数组成员存数据,这是容器节点类型
1 | typedef struct ListNode { |
但这样相当于把类型擦除了,无法在编译时检查类型。为了实现类型安全,我们需要在容器中存储类型信息。
定义一个 union,存下类型信息
1 |
Example
List(int) int_list;
好了,那怎么用上这个类型信息呢?
两种方案
- 用三目运算符约束类型,因为三目运算符两个结果必须是
is_convertible
的
1 |
Error
1 | error: pointer type mismatch ('Foo *' and 'Bar *') [-Werror,-Wpointer-type-mismatch] |
这样如果插入了一个错误类型的元素,编译器就会报错。
- 用
__typeof__
扩展 强制类型转换
1 |
这样在类型不兼容时也会报错
由于 2025年末 前的编译器不认为两处分别定义的结构相同的匿名 union/struct
是同一个类型,如果需要传递参数或者进行赋值时,需要 typedef
出一个类型
1 | typedef List(int) IntList; |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Cauphenuny's Blog!
评论