用 C 编写安全标记联合

2024-03-18

假设你正在写一个C struct它代表一顿饭中的一道菜。课程领域之一struct属于类型:

enum TP_course {STARTER, MAINCOURSE, DESSERT};

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

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

鉴于一次只会使用其中一个枚举(取决于课程的类型),因此将它们聚合在一个union:

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

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

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上面标记了联盟?也许以某种方式使其不透明?

例如,如果我写一个switch/caseenum我忘记写一个case对于一个值,编译器会触发警告,这对于以后维护代码有很大的帮助。但如果我访问stype.s无需先检查是否type==STARTER,编译器不够聪明,无法实现有风险的编码,并且根本不会发出警告。

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


经过深思熟虑后,我选择了一种方法,它可以被视为除了 PSkocik 建议的其他三种选择之外的第四种选择:重新设计struct这样就没有类型和子类型,只有子类型。那么该类型不是由struct,但是通过辅助函数。

像这样的事情:

enum TP_course {STARTER, MAINCOURSE, DESSERT};
enum TP_subtype {SALAD, GRILLEDVEGETABLES, PASTA, 
                 BEEF, LAMB, FISH, APPLEPIE, ICECREAM, MOUSSE};

struct S_course {
   enum TP_subtype stype;
   float price_in_USD;
   int availability;
   /*...*/
};

enum TP_course getCourse(struct S_course *c) {
switch(c->stype) {
   case SALAD:
   case GRILLEDVEGETABLES:
   case PASTA:
      return STARTER;
   case BEEF:
   case LAMB:
   case FISH:
      return MAINCOURSE;
   case APPLEPIE:
   case ICE-CREAM:
   case MOUSSE:
      return DESSERT;
   }
}

这种设计保证了对类型的安全读/写访问struct。它会阻止你离开struct在未定义的行为中(例如,将类型设置为 STARTER 但忘记相应地设置子类型),并且它还会阻止您读取(和写入)aunion成员说这不是当前的。

我倾向于更喜欢这种设计风格,并且我承认我受到了 Apple UI 指南的影响:创建一种设计,防止用户输入不支持/未定义的数据;当数据可以集中在一个地方时,切勿将数据分散到不同的地方;从设计中避免荒谬/非法的数据状态,这样您就不需要检查数据是否合法:它总是合法的;每当您可以对单个一般情况执行相同操作时,请避免特殊情况;等等,等等,等等……

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用 C 编写安全标记联合 的相关文章

  • 通过 SocketCAN 进行 boost::asio

    我正在考虑利用升压阿西奥 http www boost org doc libs 1 49 0 doc html boost asio html从a读取数据套接字CAN http en wikipedia org wiki SocketCA
  • QCombobox 向下箭头图像

    如何更改Qcombobox向下箭头图像 现在我正在使用这个 QSS 代码 但这不起作用 我无法删除向下箭头边框 QComboBox border 0px QComboBox down arrow border 0px background
  • 如何保证对象只有一个线程

    我有以下代码 class Service public void start creates thread which creates window and goes to message loop void stop sends WM C
  • 使用 Enumerable.OfType() 或 LINQ 查找特定类型的所有子控件

    Existed MyControl1 Controls OfType
  • ASP.NET Web API 客户端 ProgressMessageHandler Post 任务卡在 WinForm 应用程序中

    我在用着HttpClient and ProgressMessageHandler来自MS ASP NET Web API 客户端库 http nuget org packages Microsoft AspNet WebApi Clien
  • 如何在 SqlDataReader.Read() 期间从死锁异常中恢复

    我的 NET 应用程序的事件日志显示 它在从 Sql Server 读取数据时偶尔会出现死锁 这种情况通常非常罕见 因为我们已经优化了查询以避免死锁 但有时仍然会发生 过去 我们在调用ExecuteReader函数在我们的SqlComman
  • 如何获取 QTableView 的标题列表?

    我有一个QTableView我的对话框中的对象 我需要访问该表的水平标题并将它们放入QStringList object 尽管进行了大量搜索 但我在 Qt 文档中找不到如何获取此标头列表 编辑 我发现的最接近的地方是this https w
  • 如何在服务器端按钮点击时关闭当前标签页?

    我尝试在确认后关闭当前选项卡 因此我将以下代码放在确认按钮的末尾 但选项卡没有关闭 string jScript ClientScript RegisterClientScriptBlock this GetType keyClientBl
  • 检查 RoutedEvent 是否有任何处理程序

    我有一个自定义 Button 类 当单击它时 打开特定窗口 它总是执行相同的操作 我添加了一个可以在按钮的 XAML 中分配的 Click 事件 就像常规按钮一样 当它被单击时 我想执行 Click 事件处理程序 如果已分配 否则我想执行默
  • 将二进制数据从 C# 上传到 PHP

    我想将文件从 Windows C 应用程序上传到运行 PHP 的 Web 服务器 我知道 WebClient UploadFile 方法 但我希望能够分块上传文件 以便我可以监控进度并能够暂停 恢复 因此 我正在读取文件的一部分并使用 We
  • 如何通过 JsonConvert.DeserializeObject 在动态 JSON 中使用 null 条件运算符

    我正在使用 Newtonsoft 反序列化已知的 JSON 对象并从中检索一些值 如果存在 关键在于对象结构可能会不断变化 因此我使用动态来遍历结构并检索值 由于对象结构不断变化 我使用 null 条件运算符来遍历 JSON 代码看起来像这
  • 将标量添加到特征矩阵(向量)

    我刚刚开始使用 Eigen 库 无法理解如何向所有矩阵成员添加标量值 假设我有一个矩阵 Eigen Matrix3Xf mtx Eigen Matrix3Xf Ones 3 4 mtx mtx 1 main cxx 104 13 error
  • .NET Core 中的跨平台文件名处理

    如何处理文件名System IO以跨平台方式运行类以使其在 Windows 和 Linux 上运行 例如 我编写的代码在 Windows 上完美运行 但它不会在 Ubuntu Linux 上创建文件 var tempFilename Dat
  • IEnumerable.Except 不起作用,那么我该怎么办?

    我有一个 linq to sql 数据库 非常简单 我们有 3 个表 项目和用户 有一个名为 User Projects 的连接表将它们连接在一起 我已经有了一个获得的工作方法IEnumberable
  • 更改 Windows Phone 系统托盘颜色

    有没有办法将 Windows Phone 上的系统托盘颜色从黑色更改为白色 我的应用程序有白色背景 所以我希望系统托盘也是白色的 您可以在页面 XAML 中执行此操作
  • C++ Streambuf 方法可以抛出异常吗?

    我正在尝试找到一种方法来获取读取或写入流的字符数 即使存在错误并且读 写结束时间较短 该方法也是可靠的 我正在做这样的事情 return stream rdbuf gt sputn buffer buffer size 但如果streamb
  • 如何在 DropDownList 中保留空格 - ASP.net MVC Razor 视图

    我在视图中通过以下方式绑定我的模型 问题是我的项目文本是格式化文本 单词之间有空格 如下所示 123 First 234 00 123 AnotherItem 234 00 123 Second 234 00 我想保留此项目文本中的空格 即
  • 在简单注入器中解析具有自定义参数的类

    我正在使用以下命令创建 WPF MVVM 应用程序简易注射器作为 DI 容器 现在 当我尝试从简单注入器解析视图时遇到一些问题 因为我需要在构造时将参数传递到构造函数中 而不是在将视图注册到容器时 因此这不是适用的 简单注入器将值传递到构造
  • C++0x中disable_if在哪里?

    Boost 两者都有enable if and disable if 但 C 0x 似乎缺少后者 为什么它被排除在外 C 0x 中是否有元编程工具允许我构建disable if按照enable if 哦 我刚刚注意到std enable i
  • Java 和/C++ 在多线程方面的差异

    我读过一些提示 多线程实现很大程度上取决于您正在使用的目标操作系统 操作系统最终提供了多线程能力 比如Linux有POSIX标准实现 而windows32有另一种方式 但我想知道编程语言水平的主要不同 C似乎为同步提供了更多选择 例如互斥锁

随机推荐