在C中强制执行强类型检查(typedefs的类型严格性)

时间:2008-12-17 23:33:56

标签: c typedef strong-typing typechecking

有没有办法对同一类型的typedef强制执行显式转换?我要处理utf8,有时我会对字符数和字节数的索引感到困惑。所以有一些typedef很好:

typedef unsigned int char_idx_t;
typedef unsigned int byte_idx_t;

另外,你需要在它们之间进行明确的演员:

char_idx_t a = 0;
byte_idx_t b;

b = a; // compile warning
b = (byte_idx_t) a; // ok

我知道C中不存在这样的功能,但是你可能知道一个技巧或编译器扩展(更好的gcc)。


修改 我仍然不太喜欢匈牙利的符号。由于项目编码惯例,我无法将它用于此问题,但我现在在另一个类似的情况下使用它,其中类型相同且含义非常相似。我不得不承认:它有所帮助。我永远不会用起始“i”声明每个整数,但正如Joel的重叠类型示例一样,它可以挽救生命。

9 个答案:

答案 0 :(得分:19)

您可以执行以下操作:

typedef struct {
    unsigned int c_idx;
} char_idx;

typedef struct {
    unsigned int b_idx;
} byte_idx;

然后你会看到你在使用每个时间:

char_idx a;
byte_idx b;

b.b_idx = a.c_idx;  

现在更清楚的是它们是不同的类型,但仍然可以编译。

答案 1 :(得分:18)

对于“handle”类型(不透明指针),Microsoft使用声明结构的技巧,然后键入def指向结构的指针:

#define DECLARE_HANDLE(name) struct name##__ { int unused; }; \
                             typedef struct name##__ *name

然后代替

typedef void* FOOHANDLE;
typedef void* BARHANDLE;

他们这样做:

DECLARE_HANDLE(FOOHANDLE);
DECLARE_HANDLE(BARHANDLE);

现在,这有效:

FOOHANDLE make_foo();
BARHANDLE make_bar();
void do_bar(BARHANDLE);

FOOHANDLE foo = make_foo();  /* ok */
BARHANDLE bar = foo;         /* won't work! */
do_bar(foo);                 /* won't work! */   

答案 2 :(得分:14)

您想要的是“strong typedef”或“strict typedef”。

一些编程语言[Rust,D,Haskell,Ada,...]在语言层面为此提供了一些支持,C [++]没有。有人建议将其包含在名为“opaque typedef”的语言中,但未被接受。

缺乏语言支持确实不是问题。只需将要别名的类型包装到一个新类中,该类具有类型为T的1个数据成员。重复的大部分可以通过模板和宏来计算。这种简单的技术与直接支持的编程语言一样方便。

答案 3 :(得分:7)

使用棉绒。请参阅Splint:Typesstrong type check

  

强类型检查经常显示   编程错误。夹板可以检查   原始C类型更严格和   灵活地比典型的编译器(4.1)   并提供支持布尔类型   (4.2)。此外,用户可以定义   提供的抽象类型   信息隐藏(0)。

答案 4 :(得分:5)

在C中,编译器强制执行用户定义类型之间的唯一区别是结构之间的区别。任何涉及不同结构的typedef都可以工作。您的主要设计问题是不同的结构类型是否使用相同的成员名称?如果是这样,您可以使用宏和其他坏血病技巧模拟一些多态代码。如果没有,你真的致力于两种不同的表现形式。例如,您希望能够

吗?
#define INCREMENT(s, k) ((s).n += (k))

并在INCREMENTbyte_idx上使用char_idx?然后以相同的方式命名字段。

答案 5 :(得分:3)

您询问了有关扩展的信息。杰夫福斯特的CQual非常好,我认为它可以完成你想要的工作。

答案 6 :(得分:2)

如果你正在编写C ++,你可以创建两个具有不同名称的相同定义的类,这些类是unsigned int的包装器。我不知道在C中做你想做的事情的技巧。

答案 7 :(得分:2)

使用BOOST_STRONG_TYPEDEF

中定义的强类型定义

答案 8 :(得分:1)

使用C ++ 11,您可以使用枚举类,例如

enum class char_idx_t : unsigned int {};
enum class byte_idx_t : unsigned int {};

编译器将在两种类型之间强制执行显式转换;它就像一个薄的包装类。不幸的是,你不会有运算符重载,例如如果要将两个char_idx_t一起添加,则必须将它们转换为unsigned int。