首页 > 编程语言 >C++学习------cinttypes头文件的源码学习02---函数定义

C++学习------cinttypes头文件的源码学习02---函数定义

时间:2022-11-19 15:00:18浏览次数:46  
标签:cinttypes 02 const int __ char 源码 base acc


函数定义

257  __BEGIN_DECLS
258 intmax_t imaxabs(intmax_t __i) __attribute_const__ __INTRODUCED_IN(19);
259 imaxdiv_t imaxdiv(intmax_t __numerator, intmax_t __denominator) __attribute_const__ __INTRODUCED_IN(19);
260 intmax_t strtoimax(const char* __s, char** __end_ptr, int __base);
261 uintmax_t strtoumax(const char* __s, char** __end_ptr, int __base);
262 intmax_t wcstoimax(const wchar_t* __s, wchar_t** __end_ptr, int __base) __INTRODUCED_IN(21);
263 uintmax_t wcstoumax(const wchar_t* __s, wchar_t** __end_ptr, int __base) __INTRODUCED_IN(21);
264 __END_DECLS

imaxabs---返回绝对值

实现方法非常简单,判断是否大于0,大于0返回原值,小于0返回相反数。

//http://www.aospxref.com/android-12.0.0_r3/xref/bionic/libc/upstream-openbsd/lib/libc/stdlib/imaxabs.c
34 intmax_t
35 imaxabs(intmax_t j)
36 {
37 return (j < 0 ? -j : j);
38 }

imaxdiv---返回除法结果(有商有余数)

实现方法:使用整数除法'/'求商,模运算'%'求余数 注意:因为这里是有符号整数的除法,所以要考虑出现负数的情况,如果被除数大于等于0,计算后的余数小于0,那么我们要将商值加1,从余数中减去除数,即最后要保证输出的余数是正数。最后返回对应的结构体,如下:

被除数

除数


余数

>=0

>0

>=0

>=0

>=0

<0

<=0

>=0

<0

>0

<=0

<=0

<0

<0

>=0

>=0

//http://www.aospxref.com/android-12.0.0_r3/xref/bionic/libc/upstream-openbsd/lib/libc/stdlib/imaxdiv.c
36 imaxdiv_t
37 imaxdiv(intmax_t num, intmax_t denom)
38 {
39 imaxdiv_t r;
40
41 /* see div.c for comments */
42
43 r.quot = num / denom;
44 r.rem = num % denom;
45 if (num >= 0 && r.rem < 0) {
46 r.quot++;
47 r.rem -= denom;
48 }
49 return (r);
50 }

strtoimax---输入str返回对应的int值,等价于intmax_t的strtol函数

这里调用了一个模板函数来实现,模板参数为类型,该类型的最小值,最大值

//http://www.aospxref.com/android-12.0.0_r3/xref/bionic/libc/bionic/strtol.cpp
174 intmax_t strtoimax(const char* s, char** end, int base) {
175 return StrToI<intmax_t, INTMAX_MIN, INTMAX_MAX>(s, end, base);
176 }

详细分析一下模板函数

36  template <typename T, T Min, T Max> T StrToI(const char* nptr, char** endptr, int base) {

入参:const char* nptr为待转换的str,char** endptr为最后转换结束指向的字符指针,int base为进制

37    // Ensure that base is between 2 and 36 inclusive, or the special value of 0.
38 if (base < 0 || base == 1 || base > 36) {
39 if (endptr != nullptr) *endptr = const_cast<char*>(nptr);
40 errno = EINVAL;
41 return 0;
42 }
  1. 检查输入的进制是否有效,如果小于0或者等于1或者大于36,视为异常的进制,此时将endptr赋值为输入nptr首字符(如果外部输入了不为空的指针记录这个值的情况下);
44    // Skip white space and pick up leading +/- sign if any.
45 // If base is 0, allow 0x for hex and 0 for octal, else
46 // assume decimal; if base is already 16, allow 0x.
47 const char* s = nptr;
48 int c;
49 do {
50 c = *s++;
51 } while (isspace(c));
  1. 跳过前面的空格符号,直到遇到非空格符;
52    int neg;
53 if (c == '-') {
54 neg = 1;
55 c = *s++;
56 } else {
57 neg = 0;
58 if (c == '+') c = *s++;
59 }
  1. 开始检测符号,检测到'-'标记neg值然后记录指针s调到下一个,检测到'+'也同理;
60    if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X') && isxdigit(s[1])) {
61 c = s[1];
62 s += 2;
63 base = 16;
64 }
  1. 开始检测16进制,如果是0进制(默认值)或者16进制,而且当前字符(c指向的)是'0'和下一个(s指向的),是'x'或'X',而且再下一个字符(s[1])是16进制里面的字符,那么就跳过两个检测(即字符'0x'),标识为16进制;
65    if (base == 0) base = (c == '0') ? 8 : 10;
  1. 如果上一部检测16进制不是,那么如果当前的字符为'0',那就设定为8进制,否则,一律认为是10进制;
67    // We always work in the negative space because the most negative value has a
68 // larger magnitude than the most positive value.
69 T cutoff = Min / base;
70 int cutlim = -(Min % base);
  1. 因为负数表示比整数多一个数,如-128到127,我们在负数域上面进行计算,使用最小值除以进制数,得到商值cutoff和余数的负数cutlim
71    // Non-zero if any digits consumed; negative to indicate overflow/underflow.
72 int any = 0;
73 T acc = 0;
74 for (; ; c = *s++) {
75 if (isdigit(c)) {
76 c -= '0';
77 } else if (isalpha(c)) {
78 c -= isupper(c) ? 'A' - 10 : 'a' - 10;
79 } else {
80 break;
81 }
82 if (c >= base) break;
83 if (any < 0) continue;
84 if (acc < cutoff || (acc == cutoff && c > cutlim)) {
85 any = -1;
86 acc = Min;
87 errno = ERANGE;
88 } else {
89 any = 1;
90 acc *= base;
91 acc -= c;
92 }
93 }

7.使用any记录,acc记录最终的结果,开始遍历这一串字符(已经除去了正负号,进制表示);如果是数字那么c就减去字符'0'得到具体的数值,如果是字母,那就判断是大写还是小写,相应的减去('A'-10)或('a'-10)得到了具体的数值,其它符号的话就停止循环遍历,识别结束。

每次循环拿到的数值c其实就是数字最高位上面的表示,如果c>=base,说明这个字符表示超过了可以表示的进制,也直接结束;

如果any值小于0,说明在上一次的判断中,acc值已经小于了cutoff,即乘以对应的进制之后一定会突破最小值,或者(acc == cutoff && c > cutlim),本次操作完之后也会出现突破最小值的情况,所以直接将acc置为最小值,置错位标志为超出限制。

如果any值大于0,说明上一次乘法可以继续累乘。如128十进制,acc的处理如下:

  • acc = 0;
  • 检测c = 1; acc = acc*10 = 0; acc = acc - c = 0 - 1 = -1;
  • 检测c = 2; acc = acc*10 = -10; acc = acc - c = -12;
  • 检测c = 8; acc = acc10 = -120; acc = acc - c = -128; 不同于我们正常的(((110)+2)10)+8 = 128,这里使用的是(((-110)-2)*10)-8 = -128
94    if (endptr != nullptr) *endptr = const_cast<char*>(any ? s - 1 : nptr);
95 if (!neg) {
96 if (acc == Min) {
97 errno = ERANGE;
98 acc = Max;
99 } else {
100 acc = -acc;
101 }
102 }
103 return acc;
104 }

8.最后就是检测对应的结果:如果需要保存最后的指针,先check any值(是否越界),越界的话直接返回nptr指针,否则返回s的前一个(因为s是被移到下一个字符之后检测了才发现失效的,所以最后一个字符是上一个); 然后检测符号,如果是负数,那么就要处理好越界的情况,置为Max,然后赋值errno,对应的取反即可,最后返回对应值就好。

strtoumax---等价于uintmax_t的strtoul

使用无符号的模板函数进行处理,流程基本与strtoimax一致,只是这里使用的是(((1*10)+2)*10)+8 = 128这样的方式,而且没有最小值,只有最大值,可以参照代码进行相应的分析。注意:这个函数你买了也是区分了+/-符号的,也就是说输入字符串‘-128’最后在模板函数里面最后的acc取反也是可以得到acc等于-128的,但是因为返回参数为uintmax_t,那就会将-128(补码表示1000 0000)解释为unsigned类型的数据也即是128(源码表示1000 0000)

197  uintmax_t strtoumax(const char* s, char** end, int base) {
198 return StrToU<uintmax_t, UINTMAX_MAX>(s, end, base);
199 }

模板函数

106  template <typename T, T Max> T StrToU(const char* nptr, char** endptr, int base) {
107 if (base < 0 || base == 1 || base > 36) {
108 if (endptr != nullptr) *endptr = const_cast<char*>(nptr);
109 errno = EINVAL;
110 return 0;
111 }
112
113 const char* s = nptr;
114 int c;
115 do {
116 c = *s++;
117 } while (isspace(c));
118 int neg;
119 if (c == '-') {
120 neg = 1;
121 c = *s++;
122 } else {
123 neg = 0;
124 if (c == '+') c = *s++;
125 }
126 if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X') && isxdigit(s[1])) {
127 c = s[1];
128 s += 2;
129 base = 16;
130 }
131 if (base == 0) base = (c == '0') ? 8 : 10;
132
133 T cutoff = Max / static_cast<T>(base);
134 int cutlim = Max % static_cast<T>(base);
135 T acc = 0;
136 int any = 0;
137 for (; ; c = *s++) {
138 if (isdigit(c)) {
139 c -= '0';
140 } else if (isalpha(c)) {
141 c -= isupper(c) ? 'A' - 10 : 'a' - 10;
142 } else {
143 break;
144 }
145 if (c >= base) break;
146 if (any < 0) continue;
147 if (acc > cutoff || (acc == cutoff && c > cutlim)) {
148 any = -1;
149 acc = Max;
150 errno = ERANGE;
151 } else {
152 any = 1;
153 acc *= base;
154 acc += c;
155 }
156 }
157 if (neg && any > 0) acc = -acc;
158 if (endptr != nullptr) *endptr = const_cast<char*>(any ? s - 1 : nptr);
159 return acc;
160 }

wcstoimax---等价于intmax_t的wcstol

与上面的类似,只是输入为w_char,实现方案类似,不再赘述

wcstoumax---等价于uintmax_t的wcstoul

与上面的类似,只是输入为w_char,实现方案类似,不再赘述

标签:cinttypes,02,const,int,__,char,源码,base,acc
From: https://blog.51cto.com/u_15830688/5870420

相关文章

  • settings配置文件和源码
    BASE_DIR:用来在项目中构建路径SECRET_KEY:项目生成时候用的秘钥DEBUG:调试模式,在写代码的时候打开,投入使用了就不用了ALLOWED_HOSTS=['']:运行那些ip来进行访问......
  • 2022/11/19 模拟赛总结
    day-1老师说今早开家长会,我开始想今早模拟赛怎么打。然后好像就是发了五道noip的题,最后又莫名其妙加了一个noip模拟赛。day0本来说7:30起床,起晚了。然后匆匆吃了点东......
  • 2022-2023-1 20221404 《计算机基础与程序设计》第十二周学习总结
    2022-2023-120221404《计算机基础与程序设计》第十二周学习总结作业信息班级链接(2022-2023-1-计算机基础与程序设计)作业要求(2022-2023-1计算机基础与程序设......
  • MySQL 源码解读之-语法解析(四)
    MySQL源码解读之-语法解析(四)在上篇文章中,我们分析了一条sql语句select*frombank;警告bison语法解析器(MYSQLparser函数)生成的AST树的结构,如下图所示:mysql需......
  • After Effects 2022-11-19
    https://www.jianshu.com/p/66cdf4a2df9c效果和预设,搜索keylight(1.2),拖动到蓝幕的照片上。设置ScreenColor,吸管吸取要扣除的颜色screengain屏幕增益。 ......
  • 2022-2023-1 20221408《计算机基础与程序设计》第十二周学习总结
    第十二周学习总结作业信息这个作业属于哪个课程:https://edu.cnblogs.com/campus/besti/2022-2023-1-CFAP这个作业的要求在哪里:https://www.cnblogs.com/rocedu/p/95778......
  • 20221119Java基础
    publicinterfaceIService{StringNAME="default";}//等价于publicstaticfinalStringNAME="default";接口中的变量默认是publicstaticfinal的,方法默认......
  • The 2021 ICPC Asia Nanjing Regional Contest
    https://codeforces.com/gym/103470H.Crystalfly分析:可以很好的分析出一个节点最多只能选择两个儿子产生贡献过程就是u子树中xy分别为u的儿子并且t[y]=3u先到......
  • 2022弱口令实验室招新赛CTF赛道WriteUp
    Misc签到下载附件,得到一张二维码。扫码,然后根据提示“linux"操作系统,直接cat/flag,得到flag。EasyMisc下载得到EasyMisc附件,压缩包中有flag.docxWord打开,发现下......
  • 2022-2023-1 20221410 《计算机基础与程序设计》第十二周学习总结
    学期(2022-2023-1)学号20221410《计算机基础与程序设计》第十二周学习总结作业信息这个作业属于哪个课程<班级的链接>(2022-2023-1-计算机基础与程序设计)这个作......