我对通过函数strtol(),strtoll() , strtoul(),strtoull()将 C 字符串转换为整数类型的算法感兴趣。
让我们从 C 语言标准(n1570, 7.22.1.4)开始:
、
strtol、strtoll和函数[strtoul... ] 5 如果主题序列具有预期的形式并且 的值为零,则根据 6.4.4.1 的规则,从第一位数字开始的字符序列被解释为整数常量. 如果主题序列具有预期的形式并且 的值介于 2 和 36 之间,则将其用作转换的基础,将其值赋予每个字母,如上所示。如果主题序列以减号开头,则转换产生的值被否定(在返回类型中)。指向最终字符串的指针存储在 指向的对象中,前提是它不是空指针。 [... ] , ,strtoull
long int strtol(const char * restrict nptr, char ** restrict endptr, int base);basebaseendptrendptr
Returnsstrtolstrtollstrtoul, 并且strtoull函数返回转换后的值(如果有)。如果无法执行转换,则返回零。如果正确的值在可表示值的范围之外,LONG_MIN,LONG_MAX,LLONG_MIN,LLONG_MAX,ULONG_MAX, 或者ULLONG_MAX返回(根据返回类型和值的符号,如果有的话),宏的值ERANGE存储在errno.
据我了解所写内容,想法如下(不考虑非十进制基数的前导空格字符和数字系统):
- 在源代码行中,我们将丢弃减号(如果有)。
- 如果字符串包含目标类型无法表示的数字,则返回
LONG_MIN,LONG_MAX依此类推。取决于目标类型和字符串中数字的符号。并且还安装errno在ERANGE. - 让我们将字符串转换为目标类型。
- 如果源字符串中的数字以减号开头,则将减号应用于目标类型中的值。
示例 #1
errno = 0;
unsigned long long ullval = std::strtoull("-18446744073709551615", nullptr, 10);
cout << "errno: " << errno << endl;
cout << "ullval: " << ullval << endl;
cout << -18446744073709551615ULL << endl;
结论:
errno: 0
ullval: 1
1
现在没关系。
"-18446744073709551615"减号已从行中删除。- 字符串
"18446744073709551615"中的数字由 type 表示unsigned long long。 - 让我们将字符串转换为数字。
- 对结果类型中的值应用减号:
-18446744073709551615ULL == 1ULL。
示例 #2
和上一个类似,只是我们转换了字符串"-18446744073709551616"。结论:
errno: 34
ullval: 18446744073709551615
我们也得到了预期的输出。
"-18446744073709551616"减号已从行中删除。- 字符串
"18446744073709551616"中的数字不能用type表示unsigned long long。因此,我们改变errno,并返回ULLONG_MAX。
示例#3
errno = 0;
long long llval = std::strtoll("-9223372036854775808", nullptr, 10);
cout << "errno: " << errno << endl;
cout << "llval: " << llval << endl;
结论:
errno: 0
llval: -9223372036854775808
现在问题出现了。
"-9223372036854775808"减号已从行中删除。- 字符串
"9223372036854775808"中的数字不能用type表示long long。因此,有必要安装errno并返回LLONG_MIN。
为什么函数std::strtoll()返回LLONG_MIN但没有设置errno?(代码示例的链接:g++,clang)
此外,Visual Studio 2010 中的以下代码(我现在手头没有更新的代码):
errno = 0;
unsigned long ulval = std::strtoul("-4294967296", nullptr, 10);
cout << "errno: " << errno << endl;
cout << "ulval: " << ulval << endl;
产生以下输出:
errno: 34
ulval: 1
"-4294967296"丢弃减号后字符串中的数字不能用类型表示unsigned long,因此必须设置errno(发生),返回值ULONG_MAX,但函数返回1。
strtol()根据语言标准,通过函数/strtoll()及其无符号对应项将字符串转换为整数的算法是什么。我试图理解标准中的内容并没有成功。
嗯,有人投票结束了这个问题,原因是“由错字引起的问题或不可重现的问题”。
可能值得关闭,但首先,如果“问题没有重现”,那么我希望看到一个编译器示例,在执行代码后std::strtoll("-9223372036854775808", nullptr, 10),它将设置errno为非零值。
如果errno不应该设置它,那么我很乐意阅读为什么不应该设置它的解释(当然,参考标准)。