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

qui*_*ars 35 c typedef typechecking strong-typing

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

typedef unsigned int char_idx_t;
typedef unsigned int byte_idx_t;
Run Code Online (Sandbox Code Playgroud)

除此之外,您需要在它们之间进行显式转换:

char_idx_t a = 0;
byte_idx_t b;

b = a; // compile warning
b = (byte_idx_t) a; // ok
Run Code Online (Sandbox Code Playgroud)

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


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

lil*_*llq 19

你可以这样做:

typedef struct {
    unsigned int c_idx;
} char_idx;

typedef struct {
    unsigned int b_idx;
} byte_idx;
Run Code Online (Sandbox Code Playgroud)

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

char_idx a;
byte_idx b;

b.b_idx = a.c_idx;  
Run Code Online (Sandbox Code Playgroud)

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


Tim*_*her 19

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

#define DECLARE_HANDLE(name) struct name##__ { int unused; }; \
                             typedef struct name##__ *name
Run Code Online (Sandbox Code Playgroud)

然后而不是

typedef void* FOOHANDLE;
typedef void* BARHANDLE;
Run Code Online (Sandbox Code Playgroud)

他们是这样:

DECLARE_HANDLE(FOOHANDLE);
DECLARE_HANDLE(BARHANDLE);
Run Code Online (Sandbox Code Playgroud)

所以现在,这有效:

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! */   
Run Code Online (Sandbox Code Playgroud)


lib*_*ako 14

你想要什么叫做"strong typedef"或"strict typedef".

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

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


Eug*_*ota 7

使用棉绒.请参阅Splint:类型强类型检查.

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


Nor*_*sey 5

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

#define INCREMENT(s, k) ((s).n += (k))
Run Code Online (Sandbox Code Playgroud)

和使用INCREMENT上都byte_idxchar_idx?然后以相同的方式命名字段.


Joh*_*ook 2

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

  • C 对结构的工作方式相同。Microsoft 使用它来区分 windows.h 中的句柄类型。 (2认同)