避免 C 错误处理中的重复

2024-04-20

我经常编写最终成为长序列的代码,例如

int error;

error = do_something();
if (error) {
    return error;
}

error = do_something_else(with, some, args);
if (error) {
    return error;
}


error = do_something_yet_again();
if (error) {
    return error;
}

return 0;

我正在寻找一种更干净的方式来编写此内容,以在某种程度上避免重复的相同检查。到目前为止,我已经写了一个ERROR_OR宏,其工作原理类似于

#define ERROR_OR(origerr, newerr)           \
    ({                                      \
        int __error_or_origerr = (origerr); \
        (__error_or_origerr != 0)           \
                ? __error_or_origerr        \
                : (newerr);                 \
    })

这使得原始代码变得像

int error = 0;

error = ERROR_OR(error, do_something());
error = ERROR_OR(error, do_something_else(with, some, args));
error = ERROR_OR(error, do_something_yet_again());

return error;

(在我看来)这更干净一些。这也不太容易理解,因为ERROR_PRESERVE除非您阅读其文档和/或实现,否则宏并不明显。它也没有解决重复问题,只是使在一行上编写所有(现在是隐式的)检查变得更容易。

我真正想将这一切重写如下:

return ERROR_SHORT_CIRCUIT(
    do_something(),
    do_something_else(with, some, args),
    do_something_yet_again()
);

假设的ERROR_SHORT_CIRCUIT宏会

  • 在其参数列表中采用可变数量的表达式
  • 按顺序评估每个表达式
  • 如果每个表达式的计算结果为零,则其本身计算为零
  • 如果任何表达式的计算结果为非零,则立即终止并计算最后一个表达式的值

最后一个条件是我的短路与直接使用||运算符 -- 因为这将计算为 1 而不是错误值。

我最初的尝试如下:

#define ERROR_SHORT_CIRCUIT(firsterr, ...)          \
    ({                                              \
        int __error_ss_firsterr = (firsterr);       \
        (__error_ss_firsterr != ERROR_NONE)         \
                ? __error_ss_firsterr               \
                : ERROR_SHORT_CIRCUIT(__VA_ARGS__); \
    })

这有两个明显的问题:

  • 它不处理其基本情况(当__VA_ARGS__是单个值)
  • C 不支持递归宏

我研究过一些递归宏黑客 https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms#recursion,但我不喜欢使用那种程度的预处理器魔法——太多的空间可能会出现微妙的错误。我也考虑过使用真实的(可能是可变的)函数,但这需要

  • 放弃短路行为
  • 将函数作为指针传递,从而标准化它们的签名

这两个看起来都比原始的、显式的代码更糟糕。

我有兴趣听取有关处理此问题的最佳方法的建议。我对许多不同的方法持开放态度,但我的最终目标是避免重复而不损害可读性。

(我想很明显我对这个人的行为感到有些嫉妒||Ruby 等语言中的运算符)。


我会使用如下代码:

if ((error = do_something()) != 0 ||
    (error = do_something_else(with, some, args)) != 0 ||
    (error = do_something_yet_again()) != 0)
    return error;
return 0;

它是完全定义的,因为每个之前都有序列点||操作员。它实际上不需要宏。仅当您在函数调用之间分配资源或执行其他操作时,它才会遇到问题,但这与示例代码显示的不同。至少 90% 的战斗都在创造以下序列do_something_or_other()可以轻松处理错误排序的功能。

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

避免 C 错误处理中的重复 的相关文章

随机推荐

  • ASP.NET MVC 4 - 从控制器添加捆绑包?

    我的网站上有一些页面使用某些 CSS 和 JS 资源 但它们是唯一使用该 css 或 js 文件的页面 所以我不想在每个页面中都包含该 CSS 和 JS 引用 我认为我可以在控制器中创建一个捆绑包并将其添加到已经注册的捆绑包中 然后将其包含
  • 正则表达式匹配 golang 中不以 www 开头的字符串

    我有以下正则表达式 http www 预期行为 http example com Match http www example com Does not match 看起来像golang不支持负向前瞻 我怎样才能重写这个正则表达式来工作go
  • 正确使用 Servlet 中的 Stateful Bean

    目前 我们有一个注入到 Servlet 中的 Stateful bean 问题是有时我们会得到一个Caused by javax ejb ConcurrentAccessException SessionBean is executing
  • Android 位图调整大小

    调整位图大小的最佳方法是什么 Using options inSampleSize 2 Bitmap bitmap BitmapFactory decodeResource getResources R drawable mandy moo
  • .NET Remoting,为什么列表不能远程处理?

    我在用着RemotingServices Marshal and Activator GetObject在同一台计算机上的两个简单程序之间建立远程通道 public class IpcInterface MarshalByRefObject
  • Spring属性解密

    我们混合了一些尚未迁移到 spring boot 或 spring cloud 的遗留 Spring 应用程序以及 Spring Boot 应用程序 我正在创建一个 Spring 组件 如果属性值已加密且具有前缀 则该组件将在加载环境时自动
  • 如何通过继承向 Pyspark Dataframe 类添加自定义方法

    我正在尝试继承 DataFrame 类并添加其他自定义方法 如下所示 以便我可以流畅地链接并确保所有方法引用相同的数据帧 我收到异常 因为列不可迭代 from pyspark sql dataframe import DataFrame c
  • Crystal Report SP26 SetDataSource() 方法在 Visual Studio 2019 中的客户端计算机中失败

    我正在使用 Visual Studio 2019 和 Crystal Report Service Pack 26 我的代码将数据读取到 ADO NET 数据集中 并将这些数据设置为我的报告的数据源 Visual Basic Net 中类似
  • 如何使用@Configuration排除spring配置文件对其他项目的依赖

    我有一个项目 A In Maven 它依赖于项目 B In Maven 现在项目 B 得到了一些 spring Configuration db 配置 文件 这些文件在我构建和部署项目 A 时启动 但由于我的项目 A 中没有一些配置属性 它
  • AngularJS 如何防止重复的http请求?

    过去的一天我一直在为一些奇怪的情况而苦苦挣扎 发生的情况是 对于远程服务器上的 API 的 http 请求 偶尔会发送重复的请求 任何人都可以提供有关如何避免这些重复请求的帮助吗 这是我在工厂中使用的函数的示例 factory getAll
  • Rails 方式编写复杂查询

    我有这样的疑问 SELECT f id Concat f name REPLACE f parent names AS FullName u name AS Unit u id AS UnitId u position AS UnitPos
  • 如何防止从 char 数组到 bool 的隐式转换

    struct Foo void setBar bool bar bar bar bool bar int main Foo f f setBar true 由于类型转换 上面的代码编译成功 即使传递了一个 char 数组 其中bool是期待
  • 简化 if (x) Some(y) else None?

    这种常见模式感觉有点冗长 if condition Some result else None 我正在考虑使用一个函数来简化 def on A cond Boolean f gt A if cond Some f else None 这将顶
  • 后台工作者中止

    我最近尝试使用后台工作程序而不是 经典 线程 我意识到至少对我来说 它造成的问题多于解决方案 我有一个后台工作人员运行同步读取 在本例中是从串行端口 并在 1 行代码中被阻塞大约 30 秒 然后取消挂起不是解决方案 我看到 如果应用程序此时
  • 使 CSS 过渡效果适用于所有浏览器

    我目前有以下 CSS 它适用于 Google Chrome Webkit 但不适用于任何其他浏览器 使其与一切兼容的最佳方法是什么 正如你所看到的 它使用的是 webkit 但我不确定 moz 的等价物是什么 非常感谢 card margi
  • Submit() 函数有回调吗?

    我有这段代码 以及一个提交到框架的文件上传表单 setMyCookie name value 1 myform submit setMyCookie name value 2 问题 Webkit 浏览器似乎在提交表单之前或在提交表单的同时用
  • 如何使用 python selenium 单击 angularjs 链接?

    我有以下 html 其中包含使用相同类和元素的多个链接 并且我想单击具有 ng switch when next 和 python selenium 的链接 a class ng scope href a a class ng scope
  • 为什么接口变量默认是static和final?

    为什么Java中接口变量默认是static和final 来自 Philip Shaw 的 Java 界面设计常见问题解答 接口变量是静态的 因为 Java 接口不能以其自身的方式实例化 变量的值必须在不存在实例的静态上下文中分配 Final
  • matplotlib 文本标题未出现

    我无法理解为什么我的文字标题没有出现在我的绘图上 我发现文档对于图例和标题标签的放置顺序非常令人困惑 我的代码在这里 我不知道哪里出了问题 一切都按照我的预期出现 标题 轴标签 日期格式 除了标题文本根本不存在 fig plt figure
  • 避免 C 错误处理中的重复

    我经常编写最终成为长序列的代码 例如 int error error do something if error return error error do something else with some args if error re