作者icetofux ()
看板C_and_CPP
标题[问题] 纯C下的异常处理
时间Mon Nov 25 00:19:03 2019
开发平台(Platform): (Ex: Win10, Linux, ...)
无
编译器(Ex: GCC, clang, VC++...)+目标环境(跟开发平台不同的话需列出)
无
额外使用到的函数库(Library Used): (Ex: OpenGL, ...)
无
问题(Question):
因为工作上的限制,我目前都在纯C下进行程式开发,编译器可相容於C99。
最近错误处理的问题让我十分在意,一直在想有没有办法可以处理得更好、更为简洁
所以想向各位先进请益。另外这问题其实不算是C/C++专有的问题,但考量到各语言
有不同的语法、处理技巧,我尤其希望能得到C语言上的解答,所以贴在这个版,若
版主觉得不适合或还是觉得有违板规,我会再进行修正或删除。
用个简单的范例来说明,我设计一个程式,当使用者点下按钮时,将系统目前的日期
时间透过通讯发送给远端设备,我将程式拆分为三个部分:
业务逻辑层->协议处理层->硬体驱动层
业务逻辑处理一些程式运作的主流程:当使用者按下UI上的按钮,会取得目前系统时
间,并呼叫协议处理层提供的发送函式(比方说SendTime(...))。
协议处理层负责将收到的时间转换为特定的编码方式,比方说将年、月、日、时、分
、秒各自转换为长度1-byte的资料,并依序排列成一个阵列,接着呼叫硬体驱动层提
供的发送函式(比如说SendData(...))。
硬体驱动实际处理了将资料发送出去的底层行为,这部分大多是呼叫系统提供的底层
API,或是在没有OS的情况下直接进行暂存器操作。
我的问题在於,假设这三层所提供的函式中,都会有失败的风险,最常见到的处理方
式就是在每个函式都加个回传值来确认执行结果,比方说成功传True、失败传False,
或是成功传0、失败有个return code之类的。这里产生几个我觉得疑惑的地方:
1.每次呼叫函式时都要加个if检查式,写到後面发现检查跟业务逻辑用的code数量几
乎是1:1,阅读code时总会觉得业务逻辑跟检查逻辑混在一起有点难阅读,请问这
只需要去适应就好,好是有更好的方式可以处理呢?
2.我在三个层失败的时候都会留下log,可是每当发生错误时回去读log总觉得很冗余
,比方说一但有个硬体异常引起的错误,我会在log中依序看到硬体驱动层的错误讯
息、协议处理层的错误讯息、业务逻辑层的错误讯息。但其实仔细想想硬体驱动层
一但失败其他两个层根本不可能会成功,这增加除错时阅读的难度,而且实质上浪
费了系统资源(记忆体、储存媒体空间之类的),请问这部分有更好的取舍方式吗?
我不确定有没有把自己疑惑的地方好好表达清楚,如果有语意不明的地方请让我知道。
谢谢。
喂入的资料(Input):
无
预期的正确结果(Expected Output):
无
错误结果(Wrong Output):
无
程式码(Code):(请善用置底文网页, 记得排版,禁止使用图档)
无
补充说明(Supplement):
无
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 114.45.225.81 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1574612345.A.7A0.html
※ 编辑: icetofux (114.45.225.81 台湾), 11/25/2019 00:19:42
1F:推 Schottky: 这是个很值得探讨的问题,但我这阵子暂时没空回文细说 11/25 00:51
2F:→ Schottky: C 没有 try-catch 因此错误处理确实要自己做不少事 11/25 00:53
3F:→ Schottky: 第一个问题可以用 macro 包装固定的错误检查程序 11/25 00:54
4F:→ Schottky: 第二个没问题,其实出错时你会想知道 call stack 11/25 00:56
5F:→ Schottky: 底层出错时偶尔会想知道上层是哪只猪居然这样呼叫 11/25 00:56
6F:推 Schottky: 如果要集缩成一行也可以,就把错误讯息一路往上传到最 11/25 01:03
7F:→ Schottky: 上层(你这边是业务逻辑层)才写log,每一层再各自加上自 11/25 01:03
8F:→ Schottky: 己的姓名和见解,就形成了一个完整的 call stack 11/25 01:03
9F:推 Ryspon: 好奇推 11/25 02:08
10F:推 CodingMan: 我也想知道 11/25 08:44
11F:推 chuegou: 关注 11/25 09:35
12F:→ F04E: 我自己实务上也是采用Schottky的作法 11/25 10:10
13F:推 flysonics: 和Schottky相似+1 11/25 11:07
14F:→ flysonics: 不过我的习惯是写一个handler去接所有检查逻辑fail的情 11/25 11:08
15F:→ flysonics: 况 这样顺带可以从handler function下列清单 一目了然 11/25 11:09
16F:→ flysonics: 看到自己埋了哪些检查点 11/25 11:09
17F:→ flysonics: log的部分 我是会整个Task全部用一个structure去管 11/25 11:09
18F:→ flysonics: 万一底层发生问题时 只要直接将必要资讯记在structure 11/25 11:11
19F:→ flysonics: 上 到最上层时再assert卡下来 11/25 11:11
20F:→ flysonics: 没有try&catch 就自己兜个堪用的方便debug的概念 11/25 11:13
21F:推 Qbsuran: wireshark有实作出try-catch(纯C) 可以看看source 11/25 15:46
22F:推 eye5002003: 我很懒惰,所以都是抓__FILE__跟__LINE__喷一下位置 11/25 18:21
23F:→ eye5002003: 出问题的时候才来认真嵌讯息调查 11/25 18:29
24F:推 alan23273850: 我怎麽记得c++有支援try-catch 11/26 10:31
25F:推 ko27tye: c++有阿 标题问的是C 11/26 14:27
26F:推 x246libra: go的错误处理跟C有点像似 要参考一下吗 11/28 20:44
28F:→ x246libra: 跳到 Opaque errors 来看 11/28 20:45
29F:推 exeex: 做起来应该跟golang有87%像 12/01 14:12
30F:→ exeex: 不过golang可以return两个以上的变数包含err, C要另外想办 12/01 14:12
31F:→ exeex: 法 12/01 14:12
32F:→ exeex: 用macro把return包住是一个方法 12/01 14:13
33F:推 flysonics: 用macro把return包住 这样会让後面读code的人困扰吧.. 12/02 15:24
34F:→ flysonics: . 12/02 15:24
35F:→ flysonics: 你包了个一格洞在里面谁知道 12/02 15:24
36F:推 dou0228: wireshark exception + zlog, 不要用 __FILE__ 12/05 17:10