如何在不复制代码的情况下创建不可转换的C类型?

时间:2018-07-06 20:20:57

标签: c types type-conversion typedef type-safety

我有一些带有各种函数的C代码,每个函数都使用不同类型的“句柄”对象作为参数。所有这些句柄的实现都是相同的(它只是一个带有空指针和项目计数的结构),因此仅声明一个实现似乎是合乎逻辑的-但我也希望C编译器生成一个编译器用户将错误类型的句柄传递给函数时发生-time错误。

我目前的方法是使用typedef创建各种句柄类型,用于记录函数应接受的句柄类型,但是编译器会自动转换,因此不会标记类型不匹配作为错误。有没有推荐的方法可以实现这一目标,而无需为每种类型手动复制handle-struct-declaration?

玩具示例代码如下:

typedef struct _FruitHandle {
   int _numItems;
   void * _items;
} FruitHandle;

typedef FruitHandle AppleHandle;
typedef FruitHandle BananaHandle;
// imagine a number of other fruits as well

void EatAnApple(AppleHandle a) {}
void EatABanana(BananaHandle b) {}
// and so on -- each function should ONLY except its own fruit-handle-type as an argument!

int main(int argc, char ** argv)
{
   AppleHandle apple;
   BananaHandle banana;

   EatAnApple(apple);  // ok -- types match
   EatABanana(banana); // ok -- types match

   EatAnApple(banana); // type mismatch -- I want this to be a compile-time error, but it isn't!
   EatABanana(apple);  // type mismatch -- I want this to be a compile-time error, but it isn't!

   return 0;
}

2 个答案:

答案 0 :(得分:4)

您可能会发现this question的答案很有帮助。尽管C中没有显式的类型继承,但是您可以使用顶部答案中描述的惯用法来创建AppleHandle和BananaHandle。

typedef struct {
    int _numItems;
    void *_items;
} FruitHandle;

typedef struct {
    FruitHandle fruit_handle;
} AppleHandle;

typedef struct {
    FruitHandle fruit_handle;
} BananaHandle;

...

答案 1 :(得分:2)

如评论中所述,您可以使用宏:

#define FRUIT(name) typedef struct _##name {\
   int _numItems;\
   void * _items;\
} name

FRUIT(AppleHandle);
FRUIT(BananaHandle);

这扩展为:

typedef struct _AppleHandle { int _numItems; void * _items;} AppleHandle;
typedef struct _BananaHandle { int _numItems; void * _items;} BananaHandle;