39

有没有办法对相同类型的 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 的重叠类型示例一样,它可以挽救生命。

4

9 回答 9

22

对于“句柄”类型(不透明指针),Microsoft 使用声明结构然后 typedef'ing 指向该结构的指针的技巧:

#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! */   
于 2008-12-17T23:49:54.153 回答
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;  

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

于 2008-12-17T23:45:42.507 回答
14

您想要的称为“强类型定义”或“严格类型定义”。

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

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

于 2009-10-23T16:05:20.933 回答
7

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

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

于 2008-12-17T23:51:53.463 回答
5

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

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

INCREMENT在两者上byte_idx使用char_idx?然后以相同的方式命名这些字段。

于 2008-12-18T04:21:15.667 回答
3

您询问了扩展程序。Jeff Foster 的CQual非常好,我认为它可以完成您想要的工作。

于 2009-02-26T06:35:45.297 回答
3

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

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

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

于 2013-10-24T17:36:09.940 回答
2

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

于 2008-12-17T23:36:57.690 回答
1

使用BOOST_STRONG_TYPEDEF中定义的强 typedef

于 2010-05-02T13:53:20.933 回答