2 标准库 自有基础库与 delog模块

2.1.1 assert.h errno.h

  • aessert宏
    • 表达式执行时候若错了,_abort中断当前进程

#include <assert.h>
int main(int argc,char *argv[]){
	assert(argc>2);
	return 0;
}
  • 编译链接执行,执行时传入不同数量的参数,观测结果。

  • assert在代码处于测试状态时是需要的,对发布的代码,不要。
  • 引用assert.h之前加
#define NDEBUG
  • assert.h之后的C代码中assert语句失效

  • 执行某些系统操作的函数(包括标准库的函数)出现错误时,可以引用errno.h获取一个全局数据errno,来看看是啥错误。
  • 他记录(系统操作或其他符合规范的库)函数除错时的错误类型
  • 她只是一个数据,总返回最新的错误类型(某函数除错是否设置errno,要根据man从手册获取信息)

  • ctype.h含一些对字符类别判断和字符转换操作的函数接口声明
  • 下面的函数给入的是字母或数字的ASCII时返真,否则0
int isalnum(int c);
#include<assert.h>
#include <ctype.h>
int main(int argc, char * argv[]){
	assert(argc >= 2);
	assert(isalnum(argv[1][0]));
	return 0;
}

  • 这些操作,完全可通过对一个常量表操作的一系列宏来实现
  • 用常量表直接判断比调用这些库函数来得快。
  • 但不调用这些库函数而采用常量表的方式处理,
    • 更主要的原因是
      • 在很多具体业务设计时,
      • 希望能将扩展的字符类别检测处理操作和这些基础的检测处理操作合并
    • 以统一这类操作的实现和利用方式。
    • 关于通过常量表进行字符类别检测的具体方法,2.2节展开讨论

2.1.2 setjmp.h 跨函数的跳转

第一章,讨论过带上下文保护的跳转。

由于保存了上下文信息,我们可以跨越函数进行跳转,称为长跳转。

并不处处要,但有些场合值得一





A,B,C3个函数,调用关系为:A调B,B调C。当C中发现数据不需要处理或者给入数据有问题,可跨越B甚至A直接跳出。

没有这种跨越函数的跳转,你需要一层层地return。

和goto一样,这种跳转的利用,更多情况是为了降低代码逻辑复杂度。

恰当使用长跳转,可以有效提高你所设计的代码,特别是中间过程函数代码的清晰度。

从而不用增加一堆对子函数某种返回值进行判断的辅助处理代码(辅助逻辑)





另一场景则常见于多进程的模块化处理系统中,用于回到特定(初始状态)

假设手机维修店只有客户经理和维修工程师俩人。前者负责和客户沟通、订合同、等。后者负责具体维修工作。

工程师收到一个维修任务,打开手机外壳一样,就说没得搞,然后外壳也不拧上,就扔了,休息休息去忙下一个任务了。

至于客户经理怎么和客户沟通,那不是工程师的事情,最多拍个照片以做证明。





对于模块化的系统,我们假设也有两个进程,A负责计算,B负责通过socket或其他方式获取数据及发布计算结果。

两个进程之间协作,通过任务的方式推动而不是函数的方式调用。

B进程,就如同维修工程师,当给入的数据无法计算或计算导致错误时候,则直接长跳转到最初的状态,继续等待下一个任务。

当然人性化一点,多少告知一下进程A,方便它给客户端一个交代。





要完成长跳转工作,需要一个空间保存上下文信息,此空间类型为jmp_buf。

同时还需要场景记录和恢复场景,分别对应setjmp和longjmp函数。





setjmp是有返回值的,如一章所讨论,场景恢复后得根据扔过来的鞋是右脚还是左脚,判断下面的分支剧情,

只不过记录场景时还没有观众,更不会有鞋子,所以setjmp在记录场景时会返回特定的值,且区别于任何通过longjmp跳转后所得到的返回值。





对于setjmp函数本身的执行(即记录场景),它始终返回0.

而对于longjmp在恢复场景时,给入longjmp的参数则是setjmp的返回。

但即便你将longjmp的参数设置为0,setjmp也会返回1.

总之通过longjmp恢复现场后,setjmp的返回不会为0




\

#include <assert.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
static jmp_buf jmp;
float a(float i,float j){
	if(j==0){
		longjmp(jmp,2);
	}
	return i/j;
}
float b(float x1,float x2){
	return a(x1+x2,x1-x2);
}
int main(int argc,char *argv[]){
	float x1,x2;
	assert(argc >2);
	x1=atof(argv[1]);
	x2=atof(argv[2]);
	if(setjmp(jmp)==0){
		printf("(%f+%f)/(%f-%f)=%f\n",x1,x2,x1,x2,b(x1,x2));
	}else{
		printf("(%f-%f) error!\n",x1,x2);
	}
	return 0;
}

上面的目的是计算(x1+x2)/(x1-x2)。

仅仅为了举例让main调用b,b调用a来实现。

你可以编译链接后,尝试给入两个相同数值的字符串参数,来观测运行是否除错。




\

发布了558 篇原创文章 · 获赞 295 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/zhoutianzi12/article/details/90956408