1 strtol() 函数
1.1 函数原型
#include <stdlib.h> // 必须包含这个头文件才能使用 strtol()
#include <errno.h> // 包含 errno 和 ERANGE
#include <limits.h> // 包含 LONG_MAX 和 LONG_MIN
long int strtol(const char *nptr, char **endptr, int base);
1.2 功能说明
strtol() 函数用于将字符串转换为长整数(long int)。与 atoi() 和 atol() 等函数相比,strtol() 提供了更灵活、安全的转换机制,支持多种进制以及完善的错误检查。
- 参数:
- nptr:指向待转换的字符串(以空字符 \0 结尾)。
- endptr:用于存储转换结束位置的指针。如果不需要使用该信息,可以将其设置为 NULL。
- base:进制基数(取值范围为 2 到 36)。
- 若 base 为 0,则自动推断进制:
- 以 0x 或 0X 开头 → 十六进制。
- 以 0 开头(且不是 0x 或 0X)→ 八进制。
- 其他情况 → 十进制。
- 若 base 为 0,则自动推断进制:
- 返回值:
- 成功转换:返回对应的 long int 值。
- 无效输入:若未执行任何转换,返回 0。
- 溢出情况:若转换结果超出 long int 范围:
- 正溢出:返回 LONG_MAX,并设置 errno 为 ERANGE。
- 负溢出:返回 LONG_MIN,并设置 errno 为 ERANGE。
错误处理与范围检查相关概念:
- errno
- 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码。
- 作用:当 strtol() 等函数检测到错误(如数值溢出)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型。
- 使用建议:在调用 strtol() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误。
- ERANGE
- 含义:ERANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)。
- 使用场景:当 strtol() 检测到输入的字符串表示的数值超出 long int 的表示范围(过大或过小)时,会将 errno 设置为 ERANGE,表明发生了溢出错误。
- LONG_MAX 和 LONG_MIN
- 含义:LONG_MAX 和 LONG_MIN 是宏定义(定义在 <limits.h> 头文件中),分别表示 long int 类型的最大值和最小值。
- 使用场景:若输入字符串表示的数值超出 long int 的范围(正数超过 LONG_MAX 或负数低于 LONG_MIN),strtol() 会返回对应边界值(LONG_MAX 或 LONG_MIN)并设置 errno 为 ERANGE。
1.3 转换规则
- 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等。
- 识别正负号:支持在数字前添加可选的符号字符:
- '+' 表示最终数值为正数。
- '-' 表示最终数值为负数。
- 若未指定符号,默认数值为正数。
- 读取数字:根据指定的进制(base,范围为 2 到 36)解析数字字符。
- 若 base 为 0,则自动推断进制:
- 以 0x 或 0X 开头 → 十六进制。
- 以 0 开头(且不是 0x 或 0X)→ 八进制。
- 其他情况 → 十进制。
- 若 base 为 0,则自动推断进制:
- 停止转换:遇到第一个不符合当前进制规则的字符时停止解析,后续字符将被忽略。
- 返回结果:将解析的数字转换为 long int 类型返回。
- 错误处理:
- 完全成功转换:
- endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证。
- 示例:"123456789", NULL, 10 → 返回 123456789。
- 部分成功转换:
- endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证。
- 示例:"123456789abc", NULL, 10 → 返回 123456789,endptr 指向 'a'。
- 无效输入:
- endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)。
- 示例:"HelloWorld", NULL, 10 → 返回 0,endptr 指向 'H'。
- 溢出处理:需结合 errno 和 endptr 进行判断。
- 正溢出:
- 返回 LONG_MAX,并设置 errno 为 ERANGE。
- 示例:"2147483648", NULL, 10 → 返回 LONG_MAX。
- 负溢出:
- 返回 LONG_MIN,并设置 errno 为 ERANGE。
- 示例:"-2147483649", NULL, 10 → 返回 LONG_MIN。
- 正溢出:
- 完全成功转换:
转换示例:
输入字符串 | endptr 参数 | base | 返回值 | 说明 |
---|---|---|---|---|
"123456789" | NULL | 10 | 123456789 | 完全成功转换 |
"-987654321" | NULL | 10 | -987654321 | 完全成功转换(负数) |
" +123456789" | NULL | 10 | 123456789 | 忽略前导空格 |
"123456789abc" | NULL | 10 | 123456789 | 部分成功转换,endptr 指向 'a' |
"HelloWorld" | NULL | 10 | 0 | 无效输入,endptr 指向 'H' |
"1010" | NULL | 2 | 10 | 二进制转换 |
"20" | NULL | 8 | 16 | 八进制转换 |
"FF" | NULL | 16 | 255 | 十六进制转换 |
"2147483648" | NULL | 10 | LONG_MAX | 正溢出 |
"-2147483649" | NULL | 10 | LONG_MIN | 负溢出 |
1.4 注意事项
- 错误检测:
- 方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败(即无效输入)。
- 细节:
- 若 endptr == str:表示未解析出任何有效数字(如输入为 "Hello")。
- 若 *endptr != '\0':表示部分成功转换(如输入为 "123abc",endptr 指向 'a')。
- 若 *endptr == '\0':表示完全成功转换(如输入为 "123")。
- 溢出处理:
- 条件:当输入的数值超出 long int 的表示范围时,strtol() 会设置 errno 为 ERANGE。
- 行为:
- 正溢出:返回 LONG_MAX。
- 负溢出:返回 LONG_MIN。
- 建议:在调用 strtol() 前,应清除 errno(如 errno = 0),以便后续检测。
- 灵活进制:支持 2 到 36 之间的任意进制转换,若 base 为 0,则根据字符串前缀自动推断进制。
- 推荐使用:相比 atoi() 系列函数,strtol() 更安全,支持错误检查和进制转换。
1.5 示例程序
#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件才能使用 strtol()
#include <errno.h> // 包含 errno 和 ERANGE
#include <limits.h> // 包含 LONG_MAX 和 LONG_MIN
int main()
{
char *endptr; // 用于存储转换结束的位置
long int result; // 用于存储转换结果
// 示例 1:基本转换
result = strtol("123456789", &endptr, 10);
printf("转换结果1: %ld, 结束位置: %s\n", result, endptr); // 输出: 转换结果1: 123456789, 结束位置: (null)
// 示例 2:带符号的数字
result = strtol("-987654321", &endptr, 10);
printf("转换结果2: %ld, 结束位置: %s\n", result, endptr); // 输出: 转换结果2: -987654321, 结束位置: (null)
// 示例 3:带前导空格和符号
result = strtol(" +123456789", &endptr, 10);
printf("转换结果3: %ld, 结束位置: %s\n", result, endptr); // 输出: 转换结果3: 123456789, 结束位置: (null)
// 示例 4:部分有效的数字
result = strtol("123456789abc", &endptr, 10);
printf("转换结果4: %ld, 结束位置: %s\n", result, endptr); // 输出: 转换结果4: 123456789, 结束位置: abc
// 示例 5:无效输入
result = strtol("HelloWorld", &endptr, 10);
printf("转换结果5: %ld, 结束位置: %s\n", result, endptr); // 输出: 转换结果5: 0, 结束位置: HelloWorld
// 示例 6:二进制转换
result = strtol("1010", &endptr, 2);
// 二进制 1010 转换为十进制是 1*2^3 + 0*2^2 + 1*2^1 + 0*2^0 = 8 + 0 + 2 + 0 = 10
printf("转换结果6: %ld, 结束位置: %s\n", result, endptr); // 输出: 转换结果6: 10, 结束位置: (null)
// 示例 7:八进制转换
result = strtol("20", &endptr, 8);
// 八进制 20 转换为十进制是 2*8^1 + 0*8^0 = 16 + 0 = 16
printf("转换结果7: %ld, 结束位置: %s\n", result, endptr); // 输出: 转换结果7: 16, 结束位置: (null)
// 示例 8:十六进制转换
result = strtol("FF", &endptr, 16);
// 十六进制 FF 转换为十进制是 15*16^1 + 15*16^0 = 240 + 15 = 255
printf("转换结果8: %ld, 结束位置: %s\n", result, endptr); // 输出: 转换结果8: 255, 结束位置: (null)
// 示例 9:正溢出检测
errno = 0; // 重置 errno, 清除之前的错误
result = strtol("2147483648", &endptr, 10); // 超出 long int 范围(向上溢出)
// 判断是否超出范围
if (errno == ERANGE) // ERANGE 是一个宏,表示超出范围
{
// 查看 errno 与 ERANGE 的值
printf(" errno = %d, ERANGE = %d\n", errno, ERANGE); // 输出: errno = 34, ERANGE = 34
// 查看 long int 的最大值
printf(" LONG_MAX = %ld\n", LONG_MAX); // 输出: LONG_MAX = 2147483647
// 查看转换结果
printf("转换结果9: 超出范围,返回 result(LONG_MAX): %ld\n", result);
// 转换结果9: 超出范围,返回 result(LONG_MAX): 2147483647
}
else
{
printf("转换结果9: %ld\n", result);
}
// 示例 10:负溢出检测
errno = 0; // 重置 errno, 清除之前的错误
result = strtol("-2147483649", &endptr, 10); // 超出 long int 范围(向下溢出)
// 判断是否超出范围
if (errno == ERANGE) // ERANGE 是一个宏,表示超出范围
{
// 查看 errno 与 ERANGE 的值
printf(" errno = %d, ERANGE = %d\n", errno, ERANGE); // 输出: errno = 34, ERANGE = 34
// 查看 long int 的最小值
printf(" LONG_MIN = %ld\n", LONG_MIN); // 输出: LONG_MIN = -2147483648
// 查看转换结果
printf("转换结果10: 超出范围,返回 result(LONG_MIN): %ld\n", result);
// 转换结果10: 超出范围,返回 result(LONG_MIN): -2147483648
}
else
{
printf("转换结果10: %ld\n", result);
}
// 示例 11:检查转换是否完全成功
result = strtol("123abc", &endptr, 10);
// 检查是否还有未转换的字符
if (*endptr != '\0')
{
printf("转换结果11: %ld, 但字符串未完全转换\n", result); // 输出: 转换结果11: 123, 但字符串未完全转换
}
else
{
printf("转换结果11: %ld\n", result);
}
return 0;
}
程序在 VS Code 中的运行结果如下所示:
2 strtoll() 函数
2.1 函数原型
#include <stdlib.h> // 必须包含这个头文件才能使用 strtoll()
#include <errno.h> // 包含 errno 和 ERANGE
#include <limits.h> // 包含 LLONG_MAX 和 LLONG_MIN
long long int strtoll(const char *nptr, char **endptr, int base);
2.2 功能说明
strtoll() 函数用于将字符串转换为长长整数(long long int)。与 strtol() 类似,但支持更大范围的整数(long long int),并提供灵活的进制转换和错误检查机制。
- 参数:
- nptr:指向待转换的字符串(以空字符 \0 结尾)。
- endptr:用于存储转换结束位置的指针。如果不需要使用该信息,可以将其设置为 NULL。
- base:进制基数(取值范围为 2 到 36)。
- 若 base 为 0,则自动推断进制:
- 以 0x 或 0X 开头 → 十六进制。
- 以 0 开头(且不是 0x 或 0X)→ 八进制。
- 其他情况 → 十进制。
- 若 base 为 0,则自动推断进制:
- 返回值:
- 成功转换:返回对应的 long long int 值。
- 无效输入:若未执行任何转换,返回 0。
- 溢出情况:若转换结果超出 long long int 范围:
- 正溢出:返回 LLONG_MAX,并设置 errno 为 ERANGE。
- 负溢出:返回 LLONG_MIN,并设置 errno 为 ERANGE。
错误处理与范围检查相关概念:
- errno
- 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码。
- 作用:当 strtoll() 等函数检测到错误(如数值溢出)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型。
- 使用建议:在调用 strtoll() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误。
- ERANGE
- 含义:ERANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)。
- 使用场景:当 strtoll() 检测到输入的字符串表示的数值超出 long long int 的表示范围(过大或过小)时,会将 errno 设置为 ERANGE,表明发生了溢出错误。
- LLONG_MAX 和 LLONG_MIN
- 含义:LLONG_MAX 和 LLONG_MIN 是宏定义(定义在 <limits.h> 头文件中),分别表示 long long int 类型的最大值和最小值。
- 使用场景:若输入字符串表示的数值超出 long long int 的范围(正数超过 LLONG_MAX 或负数低于 LLONG_MIN),strtoll() 会返回对应边界值(LLONG_MAX 或 LLONG_MIN)并设置 errno 为 ERANGE。
2.3 转换规则
- 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等。
- 识别正负号:支持在数字前添加可选的符号字符:
- '+' 表示最终数值为正数。
- '-' 表示最终数值为负数。
- 若未指定符号,默认数值为正数。
- 读取数字:根据指定的进制(base,范围为 2 到 36)解析数字字符。
- 若 base 为 0,则自动推断进制:
- 以 0x 或 0X 开头 → 十六进制。
- 以 0 开头(且不是 0x 或 0X)→ 八进制。
- 其他情况 → 十进制。
- 若 base 为 0,则自动推断进制:
- 停止转换:遇到第一个不符合当前进制规则的字符时停止解析,后续字符将被忽略。
- 返回结果:将解析的数字转换为 long long int 类型返回。
- 错误处理:
- 完全成功转换:
- endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证。
- 示例:"123456789", NULL, 10 → 返回 123456789。
- 部分成功转换:
- endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证。
- 示例:"123456789abc", NULL, 10 → 返回 123456789,endptr 指向 'a'。
- 无效输入:
- endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)。
- 示例:"HelloWorld", NULL, 10 → 返回 0,endptr 指向 'H'。
- 溢出处理:需结合 errno 和 endptr 进行判断。
- 正溢出:
- 返回 LLONG_MAX,并设置 errno 为 ERANGE。
- 示例:"9223372036854775808", NULL, 10 → 返回 LLONG_MAX。
- 负溢出:
- 返回 LLONG_MIN,并设置 errno 为 ERANGE。
- 示例:"-9223372036854775809", NULL, 10 → 返回 LLONG_MIN。
- 正溢出:
- 完全成功转换:
转换示例:
输入字符串 | endptr 参数 | base | 返回值 | 说明 |
---|---|---|---|---|
"123456789" | NULL | 10 | 123456789 | 完全成功转换 |
"-987654321" | NULL | 10 | -987654321 | 完全成功转换(负数) |
" +123456789" | NULL | 10 | 123456789 | 忽略前导空格 |
"123456789abc" | NULL | 10 | 123456789 | 部分成功转换,endptr 指向 'a' |
"HelloWorld" | NULL | 10 | 0 | 无效输入,endptr 指向 'H' |
"1010" | NULL | 2 | 10 | 二进制转换 |
"20" | NULL | 8 | 16 | 八进制转换 |
"FF" | NULL | 16 | 255 | 十六进制转换 |
"9223372036854775808" | NULL | 10 | LLONG_MAX | 正溢出 |
"-9223372036854775809" | NULL | 10 | LLONG_MIN | 负溢出 |
2.4 注意事项
- 错误检测:
- 方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败(即无效输入)。
- 细节:
- 若 endptr == str:表示未解析出任何有效数字(如输入为 "Hello")。
- 若 *endptr != '\0':表示部分成功转换(如输入为 "123abc",endptr 指向 'a')。
- 若 *endptr == '\0':表示完全成功转换(如输入为 "123")。
- 溢出处理:
- 条件:当输入的数值超出 long long int 的表示范围时,strtoll() 会设置 errno 为 ERANGE。
- 行为:
- 正溢出:返回 LLONG_MAX。
- 负溢出:返回 LLONG_MIN。
- 建议:在调用 strtoll() 前,应清除 errno(如 errno = 0),以便后续检测。
- 灵活进制:支持 2 到 36 之间的任意进制转换,若 base 为 0,则根据字符串前缀自动推断进制。
- 推荐使用:相比 atoll() 系列函数,strtoll() 更安全,支持错误检查和进制转换。
2.5 示例程序
#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件才能使用 strtoll()
#include <errno.h> // 包含 errno 和 ERANGE
#include <limits.h> // 包含 LLONG_MAX 和 LLONG_MIN
int main()
{
char *endptr; // 用于存储转换结束的位置
long long result; // 用于存储转换结果
// 示例 1:基本转换
result = strtoll("123456789", &endptr, 10);
printf("转换结果1: %lld, 结束位置: %s\n", result, endptr); // 输出: 转换结果1: 123456789, 结束位置: (null)
// 示例 2:带符号的数字
result = strtoll("-987654321", &endptr, 10);
printf("转换结果2: %lld, 结束位置: %s\n", result, endptr); // 输出: 转换结果2: -987654321, 结束位置: (null)
// 示例 3:带前导空格和符号
result = strtoll(" +123456789", &endptr, 10);
printf("转换结果3: %lld, 结束位置: %s\n", result, endptr); // 输出: 转换结果3: 123456789, 结束位置: (null)
// 示例 4:部分有效的数字
result = strtoll("123456789abc", &endptr, 10);
printf("转换结果4: %lld, 结束位置: %s\n", result, endptr); // 输出: 转换结果4: 123456789, 结束位置: abc
// 示例 5:无效输入
result = strtoll("HelloWorld", &endptr, 10);
printf("转换结果5: %lld, 结束位置: %s\n", result, endptr); // 输出: 转换结果5: 0, 结束位置: HelloWorld
// 示例 6:二进制转换
result = strtoll("1010", &endptr, 2);
// 二进制 1010 转换为十进制是 1*2^3 + 0*2^2 + 1*2^1 + 0*2^0 = 8 + 0 + 2 + 0 = 10
printf("转换结果6: %lld, 结束位置: %s\n", result, endptr); // 输出: 转换结果6: 10, 结束位置: (null)
// 示例 7:八进制转换
result = strtoll("20", &endptr, 8);
// 八进制 20 转换为十进制是 2*8^1 + 0*8^0 = 16 + 0 = 16
printf("转换结果7: %lld, 结束位置: %s\n", result, endptr); // 输出: 转换结果7: 16, 结束位置: (null)
// 示例 8:十六进制转换
result = strtoll("FF", &endptr, 16);
// 十六进制 FF 转换为十进制是 15*16^1 + 15*16^0 = 240 + 15 = 255
printf("转换结果8: %lld, 结束位置: %s\n", result, endptr); // 输出: 转换结果8: 255, 结束位置: (null)
// 示例 9:正溢出检测
errno = 0; // 重置 errno, 清除之前的错误
result = strtoll("9223372036854775808", &endptr, 10); // 超出 long long int 范围(向上溢出)
// 判断是否超出范围
if (errno == ERANGE) // ERANGE 是一个宏,表示超出范围
{
// 查看 errno 与 ERANGE 的值
printf(" errno = %d, ERANGE = %d\n", errno, ERANGE); // 输出: errno = 34, ERANGE = 34
// 查看 long long int 的最大值
printf(" LLONG_MAX = %lld\n", LLONG_MAX); // 输出: LLONG_MAX = 9223372036854775807
// 查看转换结果
printf("转换结果9: 超出范围,返回 result(LLONG_MAX): %lld\n", result);
// 转换结果9: 超出范围,返回 result(LLONG_MAX): 9223372036854775807
}
else
{
printf("转换结果9: %lld\n", result);
}
// 示例 10:负溢出检测
errno = 0; // 重置 errno, 清除之前的错误
result = strtoll("-9223372036854775809", &endptr, 10); // 超出 long long int 范围(向下溢出)
// 判断是否超出范围
if (errno == ERANGE) // ERANGE 是一个宏,表示超出范围
{
// 查看 errno 与 ERANGE 的值
printf(" errno = %d, ERANGE = %d\n", errno, ERANGE); // 输出: errno = 34, ERANGE = 34
// 查看 long long int 的最小值
printf(" LLONG_MIN = %lld\n", LLONG_MIN); // 输出: LLONG_MIN = -9223372036854775808
// 查看转换结果
printf("转换结果10: 超出范围,返回 result(LLONG_MIN): %lld\n", result);
// 转换结果10: 超出范围,返回 result(LLONG_MIN): -9223372036854775808
}
else
{
printf("转换结果10: %lld\n", result);
}
// 示例 11:检查转换是否完全成功
result = strtoll("123abc", &endptr, 10);
// 检查是否还有未转换的字符
if (*endptr != '\0')
{
printf("转换结果11: %lld, 但字符串未完全转换\n", result); // 输出: 转换结果11: 123, 但字符串未完全转换
}
else
{
printf("转换结果11: %lld\n", result);
}
return 0;
}
程序在 VS Code 中的运行结果如下所示:
3 strtoul() 函数
3.1 函数原型
#include <stdlib.h> // 必须包含这个头文件才能使用 strtoul()
#include <errno.h> // 包含 errno 和 ERANGE
#include <limits.h> // 包含 ULONG_MAX
unsigned long int strtoul(const char *nptr, char **endptr, int base);
3.2 功能说明
strtoul() 函数用于将字符串转换为无符号长整数(unsigned long int)。与 strtol() 类似,但支持无符号整数类型,并提供灵活的进制转换和错误检查机制。
- 参数:
- nptr:指向待转换的字符串(以空字符 \0 结尾)。
- endptr:用于存储转换结束位置的指针。如果不需要使用该信息,可以将其设置为 NULL。
- base:进制基数(取值范围为 2 到 36)。
- 若 base 为 0,则自动推断进制:
- 以 0x 或 0X 开头 → 十六进制。
- 以 0 开头(且不是 0x 或 0X)→ 八进制。
- 其他情况 → 十进制。
- 若 base 为 0,则自动推断进制:
- 返回值:
- 成功转换:返回对应的 unsigned long int 值。
- 无效输入:若未执行任何转换,返回 0。
- 溢出情况:若转换结果超出 unsigned long int 范围,返回 ULONG_MAX,并设置 errno 为 ERANGE。
错误处理与范围检查相关概念:
- errno
- 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码。
- 作用:当 strtoul() 等函数检测到错误(如数值溢出)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型。
- 使用建议:在调用 strtoul() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误。
- ERANGE
- 含义:ERANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)。
- 使用场景:当 strtoul() 检测到输入的字符串表示的数值超出 unsigned long int 的表示范围(过大)时,会将 errno 设置为 ERANGE,表明发生了溢出错误。
- ULONG_MAX
- 含义:ULONG_MAX 是一个宏定义(定义在 <limits.h> 头文件中),表示 unsigned long int 类型的最大值。
- 使用场景:若输入字符串表示的数值超出 unsigned long int 的范围(正数超过 ULONG_MAX),strtoul() 会返回 ULONG_MAX 并设置 errno 为 ERANGE。
3.3 转换规则
- 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等。
- 识别正负号:
- 正号('+'):
- strtoul 允许在数字前添加正号('+'),但无符号整数(unsigned long)无法表示负数,因此正号仅作为语法形式,对结果无实际影响。
- 负号('-'):
- strtoul 不支持负数(范围为 0 到 ULONG_MAX)。
- 标准行为:停止解析,endptr 指向负号位置('-'),返回 0。
- 非标准行为:某些实现可能尝试解析负号后的数字,返回未定义值(可能是 0 或补码对应的随机值)。
- 结论:不要依赖 strtoul 解析负数,否则会导致未定义行为。
- 正号('+'):
- 读取数字:根据指定的进制(base,范围为 2 到 36)解析数字字符。
- 若 base 为 0,则自动推断进制:
- 以 0x 或 0X 开头 → 十六进制。
- 以 0 开头(且不是 0x 或 0X)→ 八进制。
- 其他情况 → 十进制。
- 若 base 为 0,则自动推断进制:
- 停止转换:遇到第一个不符合当前进制规则的字符时停止解析,后续字符将被忽略。
- 返回结果:将解析的数字转换为 unsigned long int 类型返回。
- 错误处理:
- 完全成功转换:
- endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证。
- 示例:"123456789", NULL, 10 → 返回 123456789。
- 部分成功转换:
- endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证。
- 示例:"123456789abc", NULL, 10 → 返回 123456789,endptr 指向 'a'。
- 无效输入:
- endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)。
- 示例:"HelloWorld", NULL, 10 → 返回 0,endptr 指向 'H'。
- 溢出处理:需结合 errno 和 endptr 进行判断。
- 正溢出:
- 返回 ULONG_MAX,并设置 errno 为 ERANGE。
- 示例:"4294967296", NULL, 10 → 返回 ULONG_MAX。
- 正溢出:
- 完全成功转换:
转换示例:
输入字符串 | endptr 参数 | base | 返回值 | 说明 |
---|---|---|---|---|
"123456789" | NULL | 10 | 123456789 | 完全成功转换 |
"-987654321" | NULL | 10 | 返回 0(标准行为)或未定义值(取决于实现) |
|
" +123456789" | NULL | 10 | 123456789 | 忽略前导空格后完全成功转换(正号无实际意义) |
"123456789abc" | NULL | 10 | 123456789 | 部分成功转换,endptr 指向 'a' |
"HelloWorld" | NULL | 10 | 0 | 无效输入,endptr 指向 'H' |
"1010" | NULL | 2 | 10 | 二进制转换 |
"20" | NULL | 8 | 16 | 八进制转换 |
"FF" | NULL | 16 | 255 | 十六进制转换 |
"4294967296" | NULL | 10 | ULONG_MAX | 正溢出 |
3.4 注意事项
- 错误检测:
- 方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败(即无效输入)。
- 细节:
- 若 endptr == str:表示未解析出任何有效数字(如输入为 "Hello")。
- 若 *endptr != '\0':表示部分成功转换(如输入为 "123abc",endptr 指向 'a')。
- 若 *endptr == '\0':表示完全成功转换(如输入为 "123")。
- 溢出处理:
- 条件:当输入的数值超出 unsigned long int 的表示范围时,strtoul() 会设置 errno 为 ERANGE。
- 行为:
- 正溢出:返回 ULONG_MAX。
- 建议:在调用 strtoul() 前,应清除 errno(如 errno = 0),以便后续检测。
- 灵活进制:支持 2 到 36 之间的任意进制转换,若 base 为 0,则根据字符串前缀自动推断进制。
- 推荐使用:相比 atol() 系列函数,strtoul() 更安全,支持错误检查和进制转换。
3.5 示例程序
#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件才能使用 strtoul()
#include <errno.h> // 包含 errno 和 ERANGE
#include <limits.h> // 包含 ULONG_MAX
int main()
{
char *endptr; // 用于存储转换结束的位置
unsigned long result; // 用于存储转换结果
// 示例 1:基本转换
result = strtoul("123456789", &endptr, 10);
printf("转换结果1: %lu, 结束位置: %s\n", result, endptr); // 输出: 转换结果1: 123456789, 结束位置: (null)
// 示例 2:带符号的数字
result = strtoul("-987654321", &endptr, 10);
printf("转换结果2: %lu, 结束位置: %s\n", result, endptr); // 输出: 0(标准行为)或未定义值(取决于实现)
// 示例 3:带前导空格和符号(正号无实际意义)
result = strtoul(" +123456789", &endptr, 10);
printf("转换结果3: %lu, 结束位置: %s\n", result, endptr); // 输出: 转换结果3: 123456789, 结束位置: (null)
// 示例 4:部分有效的数字
result = strtoul("123456789abc", &endptr, 10);
printf("转换结果4: %lu, 结束位置: %s\n", result, endptr); // 输出: 转换结果4: 123456789, 结束位置: abc
// 示例 5:无效输入
result = strtoul("HelloWorld", &endptr, 10);
printf("转换结果5: %lu, 结束位置: %s\n", result, endptr); // 输出: 转换结果5: 0, 结束位置: HelloWorld
// 示例 6:二进制转换
result = strtoul("1010", &endptr, 2);
// 二进制 1010 转换为十进制是 1*2^3 + 0*2^2 + 1*2^1 + 0*2^0 = 8 + 0 + 2 + 0 = 10
printf("转换结果6: %lu, 结束位置: %s\n", result, endptr); // 输出: 转换结果6: 10, 结束位置: (null)
// 示例 7:八进制转换
result = strtoul("20", &endptr, 8);
// 八进制 20 转换为十进制是 2*8^1 + 0*8^0 = 16 + 0 = 16
printf("转换结果7: %lu, 结束位置: %s\n", result, endptr); // 输出: 转换结果7: 16, 结束位置: (null)
// 示例 8:十六进制转换
result = strtoul("FF", &endptr, 16);
// 十六进制 FF 转换为十进制是 15*16^1 + 15*16^0 = 240 + 15 = 255
printf("转换结果8: %lu, 结束位置: %s\n", result, endptr); // 输出: 转换结果8: 255, 结束位置: (null)
// 示例 9:正溢出检测
errno = 0; // 重置 errno, 清除之前的错误
result = strtoul("4294967296", &endptr, 10); // 超出 unsigned long int 范围(向上溢出)
// 判断是否超出范围
if (errno == ERANGE) // ERANGE 是一个宏,表示超出范围
{
// 查看 errno 与 ERANGE 的值
printf(" errno = %d, ERANGE = %d\n", errno, ERANGE); // 输出: errno = 34, ERANGE = 34
// 查看 unsigned long int 的最大值
printf(" ULONG_MAX = %lu\n", ULONG_MAX); // 输出: ULONG_MAX = 4294967295
// 查看转换结果
printf("转换结果9: 超出范围,返回 result(ULONG_MAX): %lu\n", result);
// 转换结果9: 超出范围,返回 result(ULONG_MAX): 4294967295
}
else
{
printf("转换结果9: %lu\n", result);
}
// 示例 10:检查转换是否完全成功
result = strtoul("123abc", &endptr, 10);
// 检查是否还有未转换的字符
if (*endptr != '\0')
{
printf("转换结果10: %lu, 但字符串未完全转换\n", result); // 输出: 转换结果10: 123, 但字符串未完全转换
}
else
{
printf("转换结果10: %lu\n", result);
}
return 0;
}
程序在 VS Code 中的运行结果如下所示:
4 strtoull() 函数
4.1 函数原型
#include <stdlib.h> // 必须包含这个头文件才能使用 strtoull()
#include <errno.h> // 包含 errno 和 ERANGE
#include <limits.h> // 包含 ULLONG_MAX
unsigned long long int strtoull(const char *nptr, char **endptr, int base);
4.2 功能说明
strtoull() 函数用于将字符串转换为无符号长长整数(unsigned long long int)。与 strtoul() 类似,但支持更大的无符号整数类型,并提供灵活的进制转换和错误检查机制。
- 参数:
- nptr:指向待转换的字符串(以空字符 \0 结尾)。
- endptr:用于存储转换结束位置的指针。如果不需要使用该信息,可以将其设置为 NULL。
- base:进制基数(取值范围为 2 到 36)。
- 若 base 为 0,则自动推断进制:
- 以 0x 或 0X 开头 → 十六进制。
- 以 0 开头(且不是 0x 或 0X)→ 八进制。
- 其他情况 → 十进制。
- 若 base 为 0,则自动推断进制:
- 返回值:
- 成功转换:返回对应的 unsigned long long int 值。
- 无效输入:若未执行任何转换,返回 0。
- 溢出情况:若转换结果超出 unsigned long long int 范围,返回 ULLONG_MAX,并设置 errno 为 ERANGE。
错误处理与范围检查相关概念:
- errno
- 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码。
- 作用:当 strtoull() 等函数检测到错误(如数值溢出)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型。
- 使用建议:在调用 strtoull() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误。
- ERANGE
- 含义:ERANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)。
- 使用场景:当 strtoull() 检测到输入的字符串表示的数值超出 unsigned long long int 的表示范围(正数超过 ULLONG_MAX)时,会将 errno 设置为 ERANGE,表明发生了溢出错误。
- ULLONG_MAX
- 含义:ULLONG_MAX 是一个宏定义(定义在 <limits.h> 头文件中),表示 unsigned long long int 类型的最大值。
- 使用场景:若输入字符串表示的数值超出 unsigned long long int 的范围(正数超过 ULLONG_MAX),strtoull() 会返回 ULLONG_MAX 并设置 errno 为 ERANGE。
4.3 转换规则
- 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等。
- 识别正负号:
- 正号('+'):
- strtoull 允许在数字前添加正号('+'),但无符号整数(unsigned long long)无法表示负数,因此正号仅作为语法形式,对结果无实际影响。
- 负号('-'):
- strtoull 不支持负数(范围为 0 到 ULLONG_MAX)。
- 标准行为:停止解析,endptr 指向负号位置('-'),返回 0。
- 非标准行为:某些实现可能尝试解析负号后的数字,返回未定义值(可能是 0 或补码对应的随机值)。
- 结论:不要依赖 strtoull 解析负数,否则会导致未定义行为。
- 正号('+'):
- 读取数字:根据指定的进制(base,范围为 2 到 36)解析数字字符。
- 若 base 为 0,则自动推断进制:
- 以 0x 或 0X 开头 → 十六进制。
- 以 0 开头(且不是 0x 或 0X)→ 八进制。
- 其他情况 → 十进制。
- 若 base 为 0,则自动推断进制:
- 停止转换:遇到第一个不符合当前进制规则的字符时停止解析,后续字符将被忽略。
- 返回结果:将解析的数字转换为 unsigned long long int 类型返回。
- 错误处理:
- 完全成功转换:
- endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证。
- 示例:"12345678901234567890", NULL, 10 → 返回 12345678901234567890。
- 部分成功转换:
- endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证。
- 示例:"12345678901234567890abc", NULL, 10 → 返回 12345678901234567890,endptr 指向 'a'。
- 无效输入:
- endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)。
- 示例:"HelloWorld", NULL, 10 → 返回 0,endptr 指向 'H'。
- 溢出处理:需结合 errno 和 endptr 进行判断。
- 正溢出:
- 返回 ULLONG_MAX,并设置 errno 为 ERANGE。
- 示例:"18446744073709551616", NULL, 10 → 返回 ULLONG_MAX。
- 正溢出:
- 完全成功转换:
转换示例:
输入字符串 | endptr 参数 | base | 返回值 | 说明 |
---|---|---|---|---|
"12345678901234567890" | NULL | 10 | 12345678901234567890 | 完全成功转换 |
"-987654321" | NULL | 10 | 返回 0(标准行为)或未定义值(取决于实现) |
|
" +12345678901234567890" | NULL | 10 | 12345678901234567890 | 忽略前导空格后完全成功转换(正号无实际意义) |
"12345678901234567890abc" | NULL | 10 | 12345678901234567890 | 部分成功转换,endptr 指向 'a' |
"HelloWorld" | NULL | 10 | 0 | 无效输入,endptr 指向 'H' |
"1010" | NULL | 2 | 10 | 二进制转换 |
"20" | NULL | 8 | 16 | 八进制转换 |
"FF" | NULL | 16 | 255 | 十六进制转换 |
"18446744073709551616" | NULL | 10 | ULLONG_MAX | 正溢出 |
4.4 注意事项
- 错误检测:
- 方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败(即无效输入)。
- 细节:
- 若 endptr == str:表示未解析出任何有效数字(如输入为 "Hello")。
- 若 *endptr != '\0':表示部分成功转换(如输入为 "123abc",endptr 指向 'a')。
- 若 *endptr == '\0':表示完全成功转换(如输入为 "123")。
- 溢出处理:
- 条件:当输入的数值超出 unsigned long long int 的表示范围时,strtoull() 会设置 errno 为 ERANGE。
- 行为:
- 正溢出:返回 ULLONG_MAX。
- 建议:在调用 strtoull() 前,应清除 errno(如 errno = 0),以便后续检测。
- 灵活进制:支持 2 到 36 之间的任意进制转换,若 base 为 0,则根据字符串前缀自动推断进制。
- 推荐使用:相比 atoll() 系列函数,strtoull() 更安全,支持错误检查和进制转换。
4.5 示例程序
#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件才能使用 strtoull()
#include <errno.h> // 包含 errno 和 ERANGE
#include <limits.h> // 包含 ULLONG_MAX
int main()
{
char *endptr; // 用于存储转换结束的位置
unsigned long long result; // 用于存储转换结果
// 示例 1:基本转换
result = strtoull("12345678901234567890", &endptr, 10);
printf("转换结果1: %llu, 结束位置: %s\n", result, endptr); // 输出: 转换结果1: 12345678901234567890, 结束位置: (null)
// 示例 2:带符号的数字
result = strtoull("-987654321", &endptr, 10);
printf("转换结果2: %llu, 结束位置: %s\n", result, endptr); // 输出: 0(标准行为)或未定义值(取决于实现)
// 示例 3:带前导空格和符号(正号无实际意义)
result = strtoull(" +12345678901234567890", &endptr, 10);
printf("转换结果3: %llu, 结束位置: %s\n", result, endptr); // 输出: 转换结果3: 12345678901234567890, 结束位置: (null)
// 示例 4:部分有效的数字
result = strtoull("12345678901234567890abc", &endptr, 10);
printf("转换结果4: %llu, 结束位置: %s\n", result, endptr); // 输出: 转换结果4: 12345678901234567890, 结束位置: abc
// 示例 5:无效输入
result = strtoull("HelloWorld", &endptr, 10);
printf("转换结果5: %llu, 结束位置: %s\n", result, endptr); // 输出: 转换结果5: 0, 结束位置: HelloWorld
// 示例 6:二进制转换
result = strtoull("1010", &endptr, 2);
// 二进制 1010 转换为十进制是 1*2^3 + 0*2^2 + 1*2^1 + 0*2^0 = 8 + 0 + 2 + 0 = 10
printf("转换结果6: %llu, 结束位置: %s\n", result, endptr); // 输出: 转换结果6: 10, 结束位置: (null)
// 示例 7:八进制转换
result = strtoull("20", &endptr, 8);
// 八进制 20 转换为十进制是 2*8^1 + 0*8^0 = 16 + 0 = 16
printf("转换结果7: %llu, 结束位置: %s\n", result, endptr); // 输出: 转换结果7: 16, 结束位置: (null)
// 示例 8:十六进制转换
result = strtoull("FF", &endptr, 16);
// 十六进制 FF 转换为十进制是 15*16^1 + 15*16^0 = 240 + 15 = 255
printf("转换结果8: %llu, 结束位置: %s\n", result, endptr); // 输出: 转换结果8: 255, 结束位置: (null)
// 示例 9:正溢出检测
errno = 0; // 重置 errno, 清除之前的错误
result = strtoull("18446744073709551616", &endptr, 10); // 超出 unsigned long long int 范围(向上溢出)
// 判断是否超出范围
if (errno == ERANGE) // ERANGE 是一个宏,表示超出范围
{
// 查看 errno 与 ERANGE 的值
printf(" errno = %d, ERANGE = %d\n", errno, ERANGE); // 输出: errno = 34, ERANGE = 34
// 查看 unsigned long long int 的最大值
printf(" ULLONG_MAX = %llu\n", ULLONG_MAX); // 输出: ULLONG_MAX = 18446744073709551615
// 查看转换结果
printf("转换结果9: 超出范围,返回 result(ULLONG_MAX): %llu\n", result);
// 转换结果9: 超出范围,返回 result(ULLONG_MAX): 18446744073709551615
}
else
{
printf("转换结果9: %llu\n", result);
}
// 示例 10:检查转换是否完全成功
result = strtoull("123abc", &endptr, 10);
// 检查是否还有未转换的字符
if (*endptr != '\0')
{
printf("转换结果10: %llu, 但字符串未完全转换\n", result); // 输出: 转换结果10: 123, 但字符串未完全转换
}
else
{
printf("转换结果10: %llu\n", result);
}
return 0;
}
程序在 VS Code 中的运行结果如下所示:
5 字符串转数值函数总结
函数名 | 功能 | 返回值类型 | 转换范围 | 适用场景 | 错误处理(errno) |
---|---|---|---|---|---|
strtol | 将字符串转换为有符号长整型(long) | long | LONG_MIN 到 LONG_MAX | 需要处理正负数的有符号整数转换 | 无效输入时返回 0,溢出时返回 LONG_MIN 或 LONG_MAX,并设置 errno 为 ERANGE |
strtoll | 将字符串转换为有符号长长整型(long long) | long long | LLONG_MIN 到 LLONG_MAX | 需要处理大范围有符号整数转换 | 无效输入时返回 0,溢出时返回 LLONG_MIN 或 LLONG_MAX,并设置 errno 为 ERANGE |
strtoul | 将字符串转换为无符号长整型(unsigned long) | unsigned long | 0 到 ULONG_MAX | 需要处理非负数的无符号整数转换 | 无效输入时返回 0,溢出时返回 ULONG_MAX,并设置 errno 为 ERANGE |
strtoull | 将字符串转换为无符号长长整型(unsigned long long) | unsigned long long | 0 到 ULLONG_MAX | 需要处理大范围非负数的无符号转换 | 无效输入时返回 0,溢出时返回 ULLONG_MAX,并设置 errno 为 ERANGE |
- 头文件:所有这些函数都定义在 <stdlib.h> 头文件中,使用时需要包含该头文件。
- 错误处理细节:
- 当转换的字符串不以有效的数字字符开头时,函数将返回 0,并且如果 endptr 参数不为 NULL,则 endptr 将指向字符串的起始位置。这表明函数未能解析出任何有效的数值。
- 如果转换结果超出目标类型的范围(即大于 LONG_MAX 或小于 LONG_MIN,或大于 LLONG_MAX 或小于 LLONG_MIN),函数将返回该类型的最大值或最小值(具体取决于溢出的方向),并设置 errno 为 ERANGE。
- 如果转换结果超出目标类型的范围(即大于 ULONG_MAX 或 ULLONG_MAX),函数将返回该类型的最大值(ULONG_MAX 或 ULLONG_MAX),并设置 errno 为 ERANGE。
- 跨平台兼容性:
- 这些函数是 C 标准库的一部分,因此在大多数平台上都可用。
- 然而,不同平台上的 long 和 long long 的大小可能不同,因此在跨平台开发时需要注意数值范围的变化。