目录
1 toInt()
(1)qt_strtoll()
(2) qstrtoll()
(3)bytearrayToLongLong()
(4)toIntegral_helper
1 toInt()
下面是toInt()函数的内部实现源码
QString str("16");
int b = str.toInt();
//toInt
int QString::toInt(bool *ok, int base) const
{return toIntegral_helper<int>(constData(), size(), ok, base);
}
//toIntegral_helpertemplate <typename T> staticT toIntegral_helper(const QChar *data, int len, bool *ok, int base){// ### Qt6: use std::conditional<std::is_unsigned<T>::value, qulonglong, qlonglong>::typeconst bool isUnsigned = T(0) < T(-1);typedef typename QtPrivate::QConditional<isUnsigned, qulonglong, qlonglong>::Type Int64;typedef typename QtPrivate::QConditional<isUnsigned, uint, int>::Type Int32;// we select the right overload by casting size() to int or uintInt64 val = toIntegral_helper(data, Int32(len), ok, base);if (T(val) != val) {if (ok)*ok = false;val = 0;}return T(val);}
//toIntegral_helper
qlonglong QString::toIntegral_helper(const QChar *data, int len, bool *ok, int base)
{
#if defined(QT_CHECK_RANGE)if (base != 0 && (base < 2 || base > 36)) {qWarning("QString::toULongLong: Invalid base (%d)", base);base = 10;}
#endifreturn QLocaleData::c()->stringToLongLong(QStringView(data, len), base, ok, QLocale::RejectGroupSeparator);
}
//stringToLongLong
qlonglong QLocaleData::stringToLongLong(QStringView str, int base, bool *ok,QLocale::NumberOptions number_options) const
{CharBuff buff;if (!numberToCLocale(str, number_options, &buff)) {if (ok != nullptr)*ok = false;return 0;}return bytearrayToLongLong(buff.constData(), base, ok);
}
//bytearrayToLongLong
qlonglong QLocaleData::bytearrayToLongLong(const char *num, int base, bool *ok)
{bool _ok;const char *endptr;if (*num == '\0') {if (ok != nullptr)*ok = false;return 0;}qlonglong l = qstrtoll(num, &endptr, base, &_ok);if (!_ok) {if (ok != nullptr)*ok = false;return 0;}if (*endptr != '\0') {while (ascii_isspace(*endptr))++endptr;}if (*endptr != '\0') {// we stopped at a non-digit character after converting some digitsif (ok != nullptr)*ok = false;return 0;}if (ok != nullptr)*ok = true;return l;
}
//qstrtoll
long long
qstrtoll(const char * nptr, const char **endptr, int base, bool *ok)
{*ok = true;errno = 0;char *endptr2 = 0;long long result = qt_strtoll(nptr, &endptr2, base);if (endptr)*endptr = endptr2;if ((result == 0 || result == std::numeric_limits<long long>::min()|| result == std::numeric_limits<long long>::max())&& (errno || nptr == endptr2)) {*ok = false;return 0;}return result;
}
//qt_strtoll
/** Convert a string to a long long integer.** Assumes that the upper and lower case* alphabets and digits are each contiguous.*/
long long
qt_strtoll(const char * nptr, char **endptr, int base)
{const char *s;unsigned long long acc;char c;unsigned long long cutoff;int neg, any, cutlim;/** Skip white space and pick up leading +/- sign if any.* If base is 0, allow 0x for hex and 0 for octal, else* assume decimal; if base is already 16, allow 0x.*/s = nptr;do {c = *s++;} while (ascii_isspace(c));if (c == '-') {neg = 1;c = *s++;} else {neg = 0;if (c == '+')c = *s++;}if ((base == 0 || base == 16) &&c == '0' && (*s == 'x' || *s == 'X') &&((s[1] >= '0' && s[1] <= '9') ||(s[1] >= 'A' && s[1] <= 'F') ||(s[1] >= 'a' && s[1] <= 'f'))) {c = s[1];s += 2;base = 16;}if (base == 0)base = c == '0' ? 8 : 10;acc = any = 0;if (base < 2 || base > 36)goto noconv;/** Compute the cutoff value between legal numbers and illegal* numbers. That is the largest legal value, divided by the* base. An input number that is greater than this value, if* followed by a legal input character, is too big. One that* is equal to this value may be valid or not; the limit* between valid and invalid numbers is then based on the last* digit. For instance, if the range for quads is* [-9223372036854775808..9223372036854775807] and the input base* is 10, cutoff will be set to 922337203685477580 and cutlim to* either 7 (neg==0) or 8 (neg==1), meaning that if we have* accumulated a value > 922337203685477580, or equal but the* next digit is > 7 (or 8), the number is too big, and we will* return a range error.** Set 'any' if any `digits' consumed; make it negative to indicate* overflow.*/cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX: LLONG_MAX;cutlim = cutoff % base;cutoff /= base;for ( ; ; c = *s++) {if (c >= '0' && c <= '9')c -= '0';else if (c >= 'A' && c <= 'Z')c -= 'A' - 10;else if (c >= 'a' && c <= 'z')c -= 'a' - 10;elsebreak;if (c >= base)break;if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))any = -1;else {any = 1;acc *= base;acc += c;}}if (any < 0) {acc = neg ? LLONG_MIN : LLONG_MAX;errno = ERANGE;} else if (!any) {
noconv:errno = EINVAL;} else if (neg)acc = (unsigned long long) -(long long)acc;if (endptr != NULL)*endptr = const_cast<char *>(any ? s - 1 : nptr);return (acc);
}
从后往前分析
(1)qt_strtoll()
// 这是一个将字符串转换为长整数的函数,它接受三个参数:
// 1. 一个指向要转换的字符串的指针 nptr。
// 2. 一个指向字符的指针 endptr,如果转换成功,endptr 将被设置为字符串中第一个无法被转换的字符的位置。
// 3. 一个整数 base,用于指定数字的基数,例如十进制、十六进制等。
long long qt_strtoll(const char * nptr, char **endptr, int base) { const char *s; // s 用于保存字符串的当前位置 unsigned long long acc; // acc 用于保存累积的转换结果 char c; // c 用于保存当前字符 unsigned long long cutoff; // cutoff 用于保存转换的上限(基于正负和基数) int neg, any, cutlim; // neg 用于标记数字是否为负数,any 用于标记是否有字符被成功转换,cutlim 用于保存累积的上限(基于基数) // 跳过前导空格并获取可能存在的正负号 // 如果 base 为 0,允许使用 '0x' 表示十六进制,'0' 表示八进制,否则默认为十进制;如果 base 已经为 16,允许使用 '0x'。 // (以上注释内容是针对原文代码的逐行注释,所以这里不再翻译成英文) // 此处通过一个 do-while 循环来跳过前导空格 // c 是当前的字符,通过递增 s 来获取下一个字符 s = nptr; // 设置 s 为字符串的起始位置 do { c = *s++; // 获取下一个字符并递增 s } while (ascii_isspace(c)); // 当 c 是空格字符时继续循环 // 如果 c 是 '-',设置 neg 为 1,并将 c 设置为下一个字符 // 如果 c 是 '+',设置 neg 为 0,并将 c 设置为下一个字符 if (c == '-') { neg = 1; // 设置 neg 为 1 c = *s++; // 设置 c 为下一个字符并递增 s } else { neg = 0; // 设置 neg 为 0 if (c == '+') // 如果 c 是 '+',则设置 c 为下一个字符并递增 s c = *s++; // 设置 c 为下一个字符并递增 s } // 如果 c 是 '0',并且接下来的字符是 'x' 或 'X',并且接下来的字符是十六进制数字(0-9, A-F 或 a-f),则将 base 设置为 16,并设置 c 为接下来的字符并递增 s。 if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X') && ((s[1] >= '0' && s[1] <= '9') || (s[1] >= 'A' && s[1] <= 'F') || (s[1] >= 'a' && s[1] <= 'f'))) { c = s[1]; // 设置 c 为接下来的字符并递增 s s += 2; // 将 s 向前移动两个位置(跳过 '0x' 或 '0X') base = 16; // 设置 base 为 16 }
// 如果 base 是 0,则根据 c 的值将 base 设置回十进制。如果 c 是 '0',则将 base 设置回八进制;否则将 base 设置回十进制。 if (base == 0) { // 如果 base 是 0,则进行以下判断来设置 base 的值 base = (c == '0') ? 8 : 10; // 如果 c 是 '0',则将 base 设置回八进制;否则将 base 设置回十进制。同时设置 c 为接下来的字符并递增 s。 } acc = 0; // 设置累积结果为0any = 0; // 设置任何字符被成功转换的标志为0cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX : LLONG_MAX; // 设置转换的上下限为正负的最大值cutlim = cutoff % base; // 计算转换的上下限除以基数的结果cutoff /= base; // 将转换的上下限除以基数得到新的上限
// 根据标志判断是否发生了溢出,如果溢出,则将累积结果设置为相应的最小值或最大值,并设置errno为ERANGEif (any < 0) {acc = neg ? LLONG_MIN : LLONG_MAX; // 设置累积结果为正负的最大值errno = ERANGE; // 设置errno为ERANGE,表示溢出} else if (!any) { // 如果没有任何字符被成功转换,则设置errno为EINVALerrno = EINVAL; // 设置errno为EINVAL,表示无效的输入}
(2) qstrtoll()
long long qstrtoll(const char * nptr, const char **endptr, int base, bool *ok)
// 定义一个名为qstrtoll的函数,该函数将一个字符串转换为长整数。参数包括:要转换的字符串nptr,结束字符的指针endptr,转换的进制base,和一个指向布尔值的指针ok。 { *ok = true; // 初始化ok为true,表示转换过程开始时没有错误。 errno = 0; // 初始化errno为0,用于记录可能发生的错误。 char *endptr2 = 0; // 定义一个新的字符指针endptr2并将其初始化为0。它用于存储转换结束的位置。 long long result = qt_strtoll(nptr, &endptr2, base); // 调用qt_strtoll函数进行实际的转换操作。将转换结果存储在result变量中,并将结束位置的指针存储在endptr2中。 if (endptr) // 检查endptr是否为非空指针。如果是,则执行下面的代码块。 *endptr = endptr2; // 将endptr指向的位置设置为转换结束的位置。 if ((result == 0 || result == std::numeric_limits<long long>::min() // 检查result是否为0或者等于long long的最小值。如果是,则执行下面的代码块。 || result == std::numeric_limits<long long>::max()) // 或者等于long long的最大值。如果是,则执行下面的代码块。 && (errno || nptr == endptr2)) { // 检查errno是否为非零值或者nptr是否等于endptr2。如果是,则执行下面的代码块。 *ok = false; // 将ok设置为false,表示发生了错误。 return 0; // 返回0,表示转换失败。 } return result; // 返回转换结果result。
}
(3)bytearrayToLongLong()
// qlonglong QLocaleData::bytearrayToLongLong(const char *num, int base, bool *ok)
// 定义一个名为bytearrayToLongLong的成员函数,该函数属于QLocaleData类,用于将字符数组转换为长整型数。
// 输入参数包括:一个指向字符数组的指针num,表示要转换的字符串;一个int型的base,表示转换的进制;一个指向布尔值的指针ok,用于返回转换是否成功的信息。 { // 定义一个局部布尔变量_ok,用于存储转换是否成功的信息。 bool _ok; // 定义一个指向字符的指针endptr,用于存储转换结束的位置。 const char *endptr; // 检查输入的字符串是否为空,如果为空则返回错误。 if (*num == '\0') { // 如果ok不为空,则将其设置为false并返回0。 if (ok != nullptr) *ok = false; // 返回0,表示转换失败。 return 0; } // 调用qstrtoll函数将字符串转换为长整型数,并将转换结果存储在l中,转换结束的位置存储在endptr中,转换的结果存储在_ok中。 qlonglong l = qstrtoll(num, &endptr, base, &_ok); // 如果转换失败,则返回错误。 if (!_ok) { // 如果ok不为空,则将其设置为false并返回0。 if (ok != nullptr) *ok = false; // 返回0,表示转换失败。 return 0; } // 检查转换结束的位置是否为字符串的末尾,如果不是,则跳过之后的空白字符。 if (*endptr != '\0') { while (ascii_isspace(*endptr)) ++endptr; } // 如果转换结束的位置不是字符串的末尾,说明在转换完一些数字之后遇到了非数字字符。 if (*endptr != '\0') { // 在转换了一些数字之后遇到了一个非数字字符,设置ok为false并返回错误。 // we stopped at a non-digit character after converting some digits if (ok != nullptr) *ok = false; // 返回0,表示转换失败。 return 0; } // 设置ok为true,表示转换成功。 if (ok != nullptr) *ok = true; // 返回转换结果。 return l;
}
(4)toIntegral_helper
// T toIntegral_helper(const QChar *data, int len, bool *ok, int base) 函数接受四个参数:
// 1. const QChar *data: 一个指向字符数据的指针,这些数据应该是要转换的数字字符串。
// 2. int len: 字符数据的长度。
// 3. bool *ok: 一个指向布尔值的指针,用于指示转换是否成功。如果转换成功,它将设置为true,否则设置为false。
// 4. int base: 转换的基数,例如十进制、十六进制等。 { // ### Qt6: use std::conditional<std::is_unsigned<T>::value, qulonglong, qlonglong>::type // 在Qt6中,建议使用std::conditional来选择正确的类型。如果T是无符号整数类型,选择qulonglong,否则选择qlonglong。 const bool isUnsigned = T(0) < T(-1); // 判断T是否是无符号整数类型,如果是,isUnsigned为true,否则为false。 // 使用std::conditional来选择正确的类型。如果是无符号整数,选择qulonglong,否则选择qlonglong。 typedef typename QtPrivate::QConditional<isUnsigned, qulonglong, qlonglong>::Type Int64; // 使用std::conditional来选择正确的类型。如果是无符号整数,选择uint,否则选择int。 typedef typename QtPrivate::QConditional<isUnsigned, uint, int>::Type Int32; // 通过将len强制转换为Int32来选择正确的重载函数。这允许我们处理int和uint两种情况。 // we select the right overload by casting size() to int or uint // toIntegral_helper为另一个重载函数Int64 val = toIntegral_helper(data, Int32(len), ok, base); // 检查转换后的值是否溢出。如果溢出,我们将ok设置为false,并将val设置为0。 if (T(val) != val) { if (ok) *ok = false; val = 0; } return T(val); // 返回转换后的值。
}