用 C 编写一个安全的标记联合 [英] Writing a safe tagged union in C

查看:25
本文介绍了用 C 编写一个安全的标记联合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设您正在编写一个 C struct 来表示一餐中的一道菜.课程 struct 中的字段之一是类型:

Let's suppose you are writing a C struct which represents a course in a meal. One of the fields in the course struct is of type:

enum TP_course {STARTER, MAINCOURSE, DESSERT};

然后,根据课程类型,您有一个子类型:

Then, depending on the type of the course, you have a subtype:

enum TP_starter {SALAD, GRILLEDVEGETABLES, PASTA};
enum TP_maincourse {BEEF, LAMB, FISH};
enum TP_dessert {APPLEPIE, ICECREAM, MOUSSE};

鉴于一次只使用一个这样的枚举(取决于课程的类型),将它们聚合在一个union中是有意义的:

Given that only one of such enums will be used at a time (depending on the type of the course), it makes sense to aggregate them in a union:

union U_subtype {
   enum TP_starter s;
   enum TP_maincourse m;
   enum TP_dessert d;
};

所以课程 struct 看起来像这样:

So the course struct would look like this:

struct S_course {
   enum TP_course type;
   union U_subtype stype;
   float price_in_USD;
   int availability;
   ...and all the rest of data would follow...
};

好的,一切都清楚了,但是……我是否可以遵循任何编码策略来尝试强制安全访问上面标记为 stype 的联合?也许以某种方式使其不透明?

Ok, everything is clear, but... is there any coding strategy I could follow to try to enforce safe access to the stype tagged union above? Perhaps making it opaque in some way?

例如,如果我为 enum 编写了一个 switch/case 块,而我忘记为一个值编写一个 case ,则编译器会触发警告,这对以后维护代码有很大帮助.但是如果我访问 stype.s 而不先检查是否 type==STARTER,编译器就不能足够聪明来实现有风险的编码,并且根本不会发出警告.

For example, if I write a switch/case block for an enum and I forget to write a case for a value, the compiler will trigger a warning, which is of great help for maintaining the code in the future. But if I access stype.s without first checking if type==STARTER, the compiler cannot be smart enough for realizing of the risky coding, and won't warn at all.

我能否以某种方式组织代码,以便无法访问 U_subtype 联合的成员,除非在一个非常有限的地方,我清楚地记录了必须如何访问这些成员?

Can I organize the code in some way so that it's not possible to access the members of the U_subtype union except in a very limited place where I clearly document how the access to such members must be done?

推荐答案

您可以

  1. 隐藏整个结构并暴露作用于指针的访问器函数

.

/* header */
struct S_course; //forward declaration
enum TP_starter {SALAD, GRILLEDVEGETABLES, PASTA};
enum TP_maincourse {BEEF, LAMB, FISH};
enum TP_dessert {APPLEPIE, ICECREAM, MOUSSE};
void S_course__set_starter(struct S_course *this,  enum TP_starter starter);

//accessor functions
void S_course__set_maincourse(struct S_course *this,  enum TP_maincourse maincourse);
void S_course__set_dessert(struct S_course *this,  enum TP_dessert dessert);


/* c file */
enum TP_course {STARTER, MAINCOURSE, DESSERT};
union U_subtype {
   enum TP_starter s;
   enum TP_maincourse m;
   enum TP_dessert d;
};
struct S_course {
   enum TP_course type;
   union U_subtype stype;
   float price_in_USD;
   int availability;
   /*...*/
};
void S_course__set_starter(struct S_course *this,  enum TP_starter starter)
{
    this->type = STARTER;
    this->stype.s = starter;
}

  1. 使用尖叫的成员名称不要碰我,或者像 tagged_union 这样的名称,这应该清楚地表明它需要如何访问.

  1. Use member names that scream don't touch me, or a name like tagged_union, which should make it obvious how it needs to be accessed.

切换到 C++ 并使用其访问控制功能(私有/受保护)仅隐藏某些成员,同时允许通过公共成员/好友函数进行访问

Switch to C++ and use its access control features (private/protected) to hide only some members while allowing access through public member/friend functions

这篇关于用 C 编写一个安全的标记联合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆