看到第5章就会发现,作者用了好多包裹函数,封装原始的api,所以不可避免必须学习下unix里出错处理方面的知识。

例如:

sockfd = Socket(AF_INET,   SOCK_STRAM,   0);

函数Socket是函数api socket的包裹函数,实现如下:

int Socket(int  famlily,  int type,  int protocol)

{

int     n;

if(  ( n = socket(family, type,  protocol)  )  <  0 )

err_sys("socket error");                                // 作者的自定义函数

}

而作者又自定义了一组err_sys或error_quit出错包裹函数,原因是这样可以只用一行C代码写出错误处理代码过程:

if(出错条件)

err_sys(带任意参数数目的printf格式字符串);

而不是使用如下的繁琐的方式:

if(出错条件)

{

char buff[200];

snprintf(buff,  sizeof(buff),  带任意参数数目的printf格式字符串);

perror(buff);        // perror( ) 用来将上一个函数发生错误的原因输出到标准设备(stderr)。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno 的值来决定要输出的字符串

exit(1);

}

下面贴出作者常用的自定义出错包裹函数的代码(在作者给本书附带源码里lib目录里的error.c文件可见):

#include "unp.h"#include   <stdarg.h>        /* ANSI C header file */
#include    <syslog.h>        /* for syslog() */int       daemon_proc;        /* set nonzero by daemon_init() */static void   err_doit(int, int, const char *, va_list);/* Nonfatal error related to system call* Print message and return */void
err_ret(const char *fmt, ...)
{va_list        ap;va_start(ap, fmt);err_doit(1, LOG_INFO, fmt, ap);va_end(ap);return;
}/* Fatal error related to system call* Print message and terminate */void
err_sys(const char *fmt, ...)
{va_list        ap;va_start(ap, fmt);err_doit(1, LOG_ERR, fmt, ap);va_end(ap);exit(1);
}/* Fatal error related to system call* Print message, dump core, and terminate */void
err_dump(const char *fmt, ...)
{va_list        ap;va_start(ap, fmt);err_doit(1, LOG_ERR, fmt, ap);va_end(ap);abort();      /* dump core and terminate */exit(1);       /* shouldn't get here */
}/* Nonfatal error unrelated to system call* Print message and return */void
err_msg(const char *fmt, ...)
{va_list        ap;va_start(ap, fmt);err_doit(0, LOG_INFO, fmt, ap);va_end(ap);return;
}/* Fatal error unrelated to system call* Print message and terminate */void
err_quit(const char *fmt, ...)
{va_list        ap;va_start(ap, fmt);err_doit(0, LOG_ERR, fmt, ap);va_end(ap);exit(1);
}/* Print message and return to caller* Caller specifies "errnoflag" and "level" */static void
err_doit(int errnoflag, int level, const char *fmt, va_list ap)
{int        errno_save, n;char  buf[MAXLINE + 1];errno_save = errno;      /* value caller might want printed */
#ifdef  HAVE_VSNPRINTFvsnprintf(buf, MAXLINE, fmt, ap); /* safe */
#elsevsprintf(buf, fmt, ap);                    /* not safe */
#endifn = strlen(buf);if (errnoflag)snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));strcat(buf, "\n");if (daemon_proc) {syslog(level, buf);} else {fflush(stdout);       /* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);}return;
}

这些出错函数只有err_msg是最不严重的错误,因为他没有调用exit结束进程,或abort异常终止进程(和exit一样,也会让所有的流被关闭和冲洗),而只是return返回一下,没让进程终止。

这么多函数都围绕着error_doit 这个逻辑处理中心函数,其中第一个参数errnoflag把错误分为2种,和系统相关的错误标记为1,和系统无关的错误标记为0

第二个参数level,fatal(致命的)错误标记为LOG_ERR,unfatal(不致命的)错误标记为LOG_INFO

要知道的是,这些包裹函数不见得多省代码量,以后就会发现线程函数遇到错误时并不设置标准Unix的errno变量,而是把errno的值作为函数的返回值返回调用者。这意味着每次调用以pthread_开头的某个函数时,我们必须分配一个变量来存放函数的返回值,以便在调用err_sys前把errno变量设置成该值,为了避免引入花括号把代码弄得混乱,我们可以使用C语言的逗号操作符,把errno的赋值与err_sys的调用组合成一条语句,如下所示:

int  n;

if( (n   =  pthread_mutex_lock(&ndone_mutex))  !=  0  )

errno = n, err_sys("pthread_mutex_lock error");

如果忘记了C/C++逗号符的使用,可以联想  for(  ;  ; i++, j++),或许就想起来了。

自习推敲C代码的编写,我们可以用宏来代替函数,从而稍微提高运行时效率,不过包裹函数很少是程序性能的瓶颈所在。使用包裹技术还有助于检查哪些错误返回值通常被忽略的函数是否出错,例如close和listen。

更多作者写的包裹函数见作者提供本书的代码的lib目录里的带wrap开头的文件名的文件。

apue和unp的学习之旅05——包裹函数相关推荐

  1. java五子棋代码详解_代码详解:Java和Valohai的深度学习之旅

    全文共10735字,预计学习时长22分钟或更长 有一款生命周期管理工具(也称云服务)叫做Valohai,它有着友好的用户界面和简洁的布局设计. 许多有关Valohai的案例和文档都是基于Python和 ...

  2. Redis学习之旅--Redis的数据类型你都知道吗?

    Redis学习之旅--数据类型 Redis-Key String(字符串) list(列表) Set(集合) Hash(哈希) Zset(有序集合) geospatial hyperloglog bi ...

  3. 聊聊我的Linux学习之旅吧

    聊聊我的Linux学习之旅吧 从2017年8月份正式开始学习Linux到现在正好有1年了.因为是在校学习,而且自己又事情比较多,主要是在大二时当选了网趣工作室的社长,自己又想做出一番成绩,给自己大学留 ...

  4. 开源中国社区----我的学习之旅

    开源中国社区----我的学习之旅 1.socket实现银行排队系统 http://www.oschina.net/code/snippet_2376204_53196 2.Qt棋盘 http://ww ...

  5. Go语言学习之旅--gorm(一)

    Go语言学习之旅--gorm gorm概述 ORM简介 安装 gorm声明模型 模型定义 约定 gorm.Model gorm连接到数据库 快速入门 gorm的增删查改 增 gorm创建记录 用指定的 ...

  6. hadoop学习之旅1

    大数据介绍 大数据本质也是数据,但是又有了新的特征,包括数据来源广.数据格式多样化(结构化数据.非结构化数据.Excel文件.文本文件等).数据量大(最少也是TB级别的.甚至可能是PB级别).数据增长 ...

  7. 基于设计模式的学习之旅-----访问者模式(附源码)

    基于设计模式的学习之旅-----访问者模式 1.初始访问者模式 2.什么是访问者模式 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 3.模 ...

  8. WCF学习之旅—WCF服务的WAS寄宿(十二)

    上接    WCF学习之旅-WCF服务部署到IIS7.5(九) WCF学习之旅-WCF服务部署到应用程序(十) WCF学习之旅-WCF服务的Windows 服务程序寄宿(十一) 八.WAS宿主 IIS ...

  9. 基于 Android NDK 的学习之旅-----资源释放

    基于 Android NDK 的学习之旅-----资源释放 做上一个项目的时候因为与C引擎交互频繁,有时候会突然莫名其妙的的整个应用程序直接挂掉.因为我是学Java 开始的,所以对主动释放内存没多大概 ...

最新文章

  1. ida 中segment中的extern是什么
  2. Android进程间通信(IPC)机制Binder简要介绍和学习计划
  3. 查看tensorflow等第三方包支持平台
  4. 面试题:谈谈你对hibernate的理解
  5. 计算机文化基础分析总结,《计算机文化基础实训》教学方案设计与课题分析总结.doc...
  6. 如何用Vue实现一个全选指令
  7. 255.0.0.0子网掩码相应的cidr前缀表示法是?_六十四、前缀,后缀,中缀表达式转化求值问题...
  8. mgg mysql_MYSQL基础命令
  9. php易宝支付扫码支付代码_谈谈扫码支付
  10. 计蒜客 贝壳找房函数最值(好题,巧妙排序)
  11. BZOJ2752[HAOI2012] 高速公路(road)
  12. 同一宿主机docker之间的两种通信方式
  13. HTML 拾色器 桌面取色器
  14. 国产高分系列卫星平台介绍
  15. 扫描到计算机怎么转换为文字,扫描仪扫描出来的图片怎么转换成文字
  16. 重温经典,续写传奇,迈巴赫S600改铱银色加铁灰色双拼喷漆
  17. $timeout、$interval和$watch用法
  18. 一见钟情 歌词 翻译
  19. android studio jni.h 红色报错
  20. selenium+python抓取微博时遇到“展开全文”

热门文章

  1. java字符串转成utf-8_将字符串的编码格式转换为utf-8
  2. java的八种基本数据类型
  3. 数据分析方法——判别分析
  4. 原来微信还有这三个实用小技巧!简直太方便了
  5. 明日又天涯——蝶舞萧霞
  6. FlexRay总线原理及应用
  7. dpi和ppi换算_DPI、PPI、DP、PX 的详细计算方法及算法来源是什么?
  8. 3. fooView rxjava + rxandroid + retrofit 安卓开发框架搭配 az kj
  9. centos下zip压缩解压缩命令
  10. arista 交换机镜像端口配置(将某一端口的数据转发到指定端口)