【问题标题】:How to create non-convertible C types without duplicating code?如何在不复制代码的情况下创建不可转换的 C 类型?
【发布时间】:2018-12-15 11:02:10
【问题描述】:

我有一些带有各种函数的 C 代码,每个函数都将不同类型的“句柄”对象作为参数。所有这些句柄的实现都是相同的(它只是一个带有 void-pointer 和 item-count 的结构),所以只声明一个实现似乎是合乎逻辑的——但我也希望 C 编译器生成一个 compile - 当用户将错误类型的句柄传递给函数时的时间错误。

我当前的方法使用typedef 创建各种句柄类型,它可以记录函数应该接受的句柄类型,但编译器会自动转换,因此它不会将类型不匹配标记为错误.有没有推荐的方法来实现这一点,不需要为每种类型手动复制我的句柄结构声明?

玩具示例代码如下:

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;
}

【问题讨论】:

  • 您可以编写一个宏来定义这些结构。我认为没有比这更好的了。
  • 确实如此。 typedef 是一个别名,您需要的是相互不兼容的类型
  • 弱点似乎是当你带了一个程序不知道的水果时。已知水果是硬编码的,但不接受软水果。
  • 我宁愿创建具有FruitHandle 字段的结构。因此,您可以使用其独特的属性扩展每个 Fruit...
  • 而且,如果你的结构真的是 12 字节,那么编译器进行类型检查的好处远远超过节省 24 字节的存储空间。

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


【解决方案1】:

您可能会发现this question 的答案很有帮助。虽然 C 中没有显式类型继承,但您可以使用最佳答案中描述的惯用语来创建 AppleHandle 和 BananaHandle。

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

typedef struct {
    FruitHandle fruit_handle;
} AppleHandle;

typedef struct {
    FruitHandle fruit_handle;
} BananaHandle;

...

【讨论】:

    【解决方案2】:

    如 cmets 中所述,您可以使用宏来做到这一点:

    #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;
    

    【讨论】:

    • 以下划线后跟大写字母的标识符保留供任何使用。我只是让结构标记与类型名称相同。无论如何,它们位于不同的名称空间中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-04
    • 2020-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-21
    • 1970-01-01
    相关资源
    最近更新 更多