当前位置: 首页 > news >正文

34 C 语言字符串转数值函数详解:strtol、strtoll、strtoul、strtoull(含 errno 处理、ERANGE 错误)

1 strtol() 函数

1.1 函数原型

#include <stdlib.h> // 必须包含这个头文件才能使用 strtol()
#include <errno.h>  // 包含 errno 和 ERANGE
#include <limits.h> // 包含 LONG_MAX 和 LONG_MINlong 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)→ 八进制
        • 其他情况 → 十进制
  • 返回值:
    • 成功转换:返回对应的 long int 值
    • 无效输入:若未执行任何转换,返回 0
    • 溢出情况:若转换结果超出 long int 范围
      • 正溢出:返回 LONG_MAX,并设置 errno ERANGE
      • 负溢出:返回 LONG_MIN,并设置 errno ERANGE

错误处理与范围检查相关概念:

  1. errno
    • 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码
    • 作用:当 strtol() 等函数检测到错误(如数值溢出)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型
    • 使用建议:在调用 strtol() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误
  2. ERANGE
    • 含义:ERANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)
    • 使用场景:当 strtol() 检测到输入的字符串表示的数值超出 long int 的表示范围(过大或过小)时,会将 errno 设置为 ERANGE,表明发生了溢出错误
  3. 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 转换规则

  1. 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等
  2. 识别正负号:支持在数字前添加可选的符号字符
    1. '+' 表示最终数值为正数
    2. '-' 表示最终数值为负数
    3. 若未指定符号,默认数值为正数
  3. 读取数字:根据指定的进制(base,范围为 2 到 36)解析数字字符
    1. 若 base 为 0,则自动推断进制
      1. 以 0x 或 0X 开头 → 十六进制
      2. 以 0 开头(且不是 0x 或 0X)→ 八进制
      3. 其他情况 → 十进制
  4. 停止转换:遇到第一个不符合当前进制规则的字符时停止解析,后续字符将被忽略
  5. 返回结果:将解析的数字转换为 long int 类型返回
  6. 错误处理:
    1. 完全成功转换:
      1. endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证
      2. 示例:"123456789", NULL, 10 → 返回 123456789。
    2. 部分成功转换:
      1. endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证
      2. 示例:"123456789abc", NULL, 10 → 返回 123456789,endptr 指向 'a'。
    3. 无效输入:
      1. endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)
      2. 示例:"HelloWorld", NULL, 10 → 返回 0,endptr 指向 'H'。
    4. 溢出处理:需结合 errno 和 endptr 进行判断
      1. 正溢出:
        1. 返回 LONG_MAX,并设置 errno 为 ERANGE
        2. 示例:"2147483648", NULL, 10 → 返回 LONG_MAX。
      2. 负溢出:
        1. 返回 LONG_MIN,并设置 errno 为 ERANGE
        2. 示例:"-2147483649", NULL, 10 → 返回 LONG_MIN。

        转换示例:

输入字符串endptr 参数base返回值说明
"123456789"NULL10123456789完全成功转换
"-987654321"NULL10-987654321完全成功转换(负数)
"    +123456789"NULL10123456789忽略前导空格
"123456789abc"NULL10123456789部分成功转换,endptr 指向 'a'
"HelloWorld"NULL100无效输入,endptr 指向 'H'
"1010"NULL210二进制转换
"20"NULL816八进制转换
"FF"NULL16255十六进制转换
"2147483648"NULL10LONG_MAX正溢出
"-2147483649"NULL10LONG_MIN负溢出

1.4 注意事项

  1. 错误检测:
    1. 方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败(即无效输入)
    2. 细节:
      1. 若 endptr == str:表示未解析出任何有效数字(如输入为 "Hello")
      2. 若 *endptr != '\0':表示部分成功转换(如输入为 "123abc",endptr 指向 'a')
      3. 若 *endptr == '\0':表示完全成功转换(如输入为 "123")
  2. 溢出处理:
    1. 条件:当输入的数值超出 long int 的表示范围时,strtol() 会设置 errno 为 ERANGE
    2. 行为:
      1. 正溢出:返回 LONG_MAX
      2. 负溢出:返回 LONG_MIN
    3. 建议:在调用 strtol() 前,应清除 errno(如 errno = 0),以便后续检测
  3. 灵活进制:支持 2 到 36 之间的任意进制转换,若 base 为 0,则根据字符串前缀自动推断进制
  4. 推荐使用:相比 atoi() 系列函数,strtol() 更安全,支持错误检查和进制转换

1.5 示例程序

#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件才能使用 strtol()
#include <errno.h>  // 包含 errno 和 ERANGE
#include <limits.h> // 包含 LONG_MAX 和 LONG_MINint 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 = 10printf("转换结果6: %ld, 结束位置: %s\n", result, endptr); // 输出: 转换结果6: 10, 结束位置: (null)// 示例 7:八进制转换result = strtol("20", &endptr, 8);// 八进制 20 转换为十进制是 2*8^1 + 0*8^0 = 16 + 0 = 16printf("转换结果7: %ld, 结束位置: %s\n", result, endptr); // 输出: 转换结果7: 16, 结束位置: (null)// 示例 8:十六进制转换result = strtol("FF", &endptr, 16);// 十六进制 FF 转换为十进制是 15*16^1 + 15*16^0 = 240 + 15 = 255printf("转换结果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_MINlong 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)→ 八进制
        • 其他情况 → 十进制
  • 返回值:
    • 成功转换:返回对应的 long long int 值
    • 无效输入:若未执行任何转换,返回 0
    • 溢出情况:若转换结果超出 long long int 范围
      • 正溢出:返回 LLONG_MAX,并设置 errno ERANGE
      • 负溢出:返回 LLONG_MIN,并设置 errno ERANGE

错误处理与范围检查相关概念:

  1. errno
    • 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码
    • 作用:当 strtoll() 等函数检测到错误(如数值溢出)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型
    • 使用建议:在调用 strtoll() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误
  2. ERANGE
    • 含义:ERANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)
    • 使用场景:当 strtoll() 检测到输入的字符串表示的数值超出 long long int 的表示范围(过大或过小)时,会将 errno 设置为 ERANGE,表明发生了溢出错误
  3. 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 转换规则

  1. 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等
  2. 识别正负号:支持在数字前添加可选的符号字符
    1. '+' 表示最终数值为正数
    2. '-' 表示最终数值为负数
    3. 若未指定符号,默认数值为正数
  3. 读取数字:根据指定的进制(base,范围为 2 到 36)解析数字字符
    1. 若 base 为 0,则自动推断进制
      1. 以 0x 或 0X 开头 → 十六进制
      2. 以 0 开头(且不是 0x 或 0X)→ 八进制
      3. 其他情况 → 十进制
  4. 停止转换:遇到第一个不符合当前进制规则的字符时停止解析,后续字符将被忽略
  5. 返回结果:将解析的数字转换为 long long int 类型返回
  6. 错误处理:
    1. 完全成功转换:
      1. endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证
      2. 示例:"123456789", NULL, 10 → 返回 123456789。
    2. 部分成功转换:
      1. endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证
      2. 示例:"123456789abc", NULL, 10 → 返回 123456789,endptr 指向 'a'。
    3. 无效输入:
      1. endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)
      2. 示例:"HelloWorld", NULL, 10 → 返回 0,endptr 指向 'H'。
    4. 溢出处理:需结合 errno 和 endptr 进行判断
      1. 正溢出:
        1. 返回 LLONG_MAX,并设置 errno 为 ERANGE
        2. 示例:"9223372036854775808", NULL, 10 → 返回 LLONG_MAX。
      2. 负溢出:
        1. 返回 LLONG_MIN,并设置 errno 为 ERANGE
        2. 示例:"-9223372036854775809", NULL, 10 → 返回 LLONG_MIN。

        转换示例:

输入字符串endptr 参数base返回值说明
"123456789"NULL10123456789完全成功转换
"-987654321"NULL10-987654321完全成功转换(负数)
"    +123456789"NULL10123456789忽略前导空格
"123456789abc"NULL10123456789部分成功转换,endptr 指向 'a'
"HelloWorld"NULL100无效输入,endptr 指向 'H'
"1010"NULL210二进制转换
"20"NULL816八进制转换
"FF"NULL16255十六进制转换
"9223372036854775808"NULL10LLONG_MAX正溢出
"-9223372036854775809"NULL10LLONG_MIN负溢出

2.4 注意事项

  1. 错误检测:
    1. 方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败(即无效输入)
    2. 细节:
      1. 若 endptr == str:表示未解析出任何有效数字(如输入为 "Hello")
      2. 若 *endptr != '\0':表示部分成功转换(如输入为 "123abc",endptr 指向 'a')
      3. 若 *endptr == '\0':表示完全成功转换(如输入为 "123")
  2. 溢出处理:
    1. ​​​​​​​条件:当输入的数值超出 long long int 的表示范围时,strtoll() 会设置 errno 为 ERANGE
    2. 行为:
      1. 正溢出:返回 LLONG_MAX
      2. 负溢出:返回 LLONG_MIN
    3. 建议:在调用 strtoll() 前,应清除 errno(如 errno = 0),以便后续检测
  3. 灵活进制:支持 2 到 36 之间的任意进制转换,若 base 为 0,则根据字符串前缀自动推断进制
  4. 推荐使用:相比 atoll() 系列函数,strtoll() 更安全,支持错误检查和进制转换

2.5 示例程序

#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件才能使用 strtoll()
#include <errno.h>  // 包含 errno 和 ERANGE
#include <limits.h> // 包含 LLONG_MAX 和 LLONG_MINint 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 = 10printf("转换结果6: %lld, 结束位置: %s\n", result, endptr); // 输出: 转换结果6: 10, 结束位置: (null)// 示例 7:八进制转换result = strtoll("20", &endptr, 8);// 八进制 20 转换为十进制是 2*8^1 + 0*8^0 = 16 + 0 = 16printf("转换结果7: %lld, 结束位置: %s\n", result, endptr); // 输出: 转换结果7: 16, 结束位置: (null)// 示例 8:十六进制转换result = strtoll("FF", &endptr, 16);// 十六进制 FF 转换为十进制是 15*16^1 + 15*16^0 = 240 + 15 = 255printf("转换结果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_MAXunsigned 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)→ 八进制
        • 其他情况 → 十进制
  • 返回值:
    • 成功转换:返回对应的 unsigned long int 值
    • 无效输入:若未执行任何转换,返回 0
    • 溢出情况:若转换结果超出 unsigned long int 范围,返回 ULONG_MAX,并设置 errno ERANGE

错误处理与范围检查相关概念:

  1. errno
    • 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码
    • 作用:当 strtoul() 等函数检测到错误(如数值溢出)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型
    • 使用建议:在调用 strtoul() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误
  2. ERANGE
    • 含义:ERANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)
    • 使用场景:当 strtoul() 检测到输入的字符串表示的数值超出 unsigned long int 的表示范围(过大)时,会将 errno 设置为 ERANGE,表明发生了溢出错误
  3. ULONG_MAX
    • 含义:ULONG_MAX 是一个宏定义(定义在 <limits.h> 头文件中),表示 unsigned long int 类型的最大值
    • 使用场景:若输入字符串表示的数值超出 unsigned long int 的范围(正数超过 ULONG_MAX),strtoul() 会返回 ULONG_MAX 并设置 errno 为 ERANGE

3.3 转换规则

  1. 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等
  2. 识别正负号:
    1. 正号('+'):
      1. ​​​​​​​​​​​​​​strtoul 允许在数字前添加正号('+'),但无符号整数(unsigned long)无法表示负数,因此正号仅作为语法形式,对结果无实际影响
    2. 负号('-'):
      1. ​​​​​​​​​​​​​​strtoul 不支持负数(范围为 0 到 ULONG_MAX)
      2. 标准行为:停止解析,endptr 指向负号位置('-'),返回 0
      3. 非标准行为:某些实现可能尝试解析负号后的数字,返回未定义值(可能是 0 或补码对应的随机值)
      4. 结论:不要依赖 strtoul 解析负数,否则会导致未定义行为
  3. 读取数字:根据指定的进制(base,范围为 2 到 36)解析数字字符
    1. 若 base 为 0,则自动推断进制
      1. 以 0x 或 0X 开头 → 十六进制
      2. 以 0 开头(且不是 0x 或 0X)→ 八进制
      3. 其他情况 → 十进制
  4. 停止转换:遇到第一个不符合当前进制规则的字符时停止解析,后续字符将被忽略
  5. 返回结果:将解析的数字转换为 unsigned long int 类型返回
  6. 错误处理:
    1. 完全成功转换:
      1. endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证
      2. 示例:"123456789", NULL, 10 → 返回 123456789。
    2. 部分成功转换:
      1. endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证
      2. 示例:"123456789abc", NULL, 10 → 返回 123456789,endptr 指向 'a'。
    3. 无效输入:
      1. endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)
      2. 示例:"HelloWorld", NULL, 10 → 返回 0,endptr 指向 'H'。
    4. 溢出处理:需结合 errno 和 endptr 进行判断
      1. 正溢出:
        1. 返回 ULONG_MAX,并设置 errno 为 ERANGE
        2. 示例:"4294967296", NULL, 10 → 返回 ULONG_MAX。

        转换示例:

输入字符串endptr 参数base返回值说明
"123456789"NULL10123456789完全成功转换
"-987654321"NULL10

返回 0(标准行为)或未定义值(取决于实现)

"    +123456789"NULL10123456789忽略前导空格后完全成功转换(正号无实际意义)
"123456789abc"NULL10123456789部分成功转换,endptr 指向 'a'
"HelloWorld"NULL100无效输入,endptr 指向 'H'
"1010"NULL210二进制转换
"20"NULL816八进制转换
"FF"NULL16255十六进制转换
"4294967296"NULL10ULONG_MAX正溢出

3.4 注意事项

  1. 错误检测:
    1. ​​​​​​​​​​​​​​方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败(即无效输入)
    2. 细节:
      1. 若 endptr == str:表示未解析出任何有效数字(如输入为 "Hello")
      2. 若 *endptr != '\0':表示部分成功转换(如输入为 "123abc",endptr 指向 'a')
      3. 若 *endptr == '\0':表示完全成功转换(如输入为 "123")
  2. 溢出处理:
    1. ​​​​​​​​​​​​​​条件:当输入的数值超出 unsigned long int 的表示范围时,strtoul() 会设置 errno 为 ERANGE
    2. 行为:
      1. 正溢出:返回 ULONG_MAX
    3. 建议:在调用 strtoul() 前,应清除 errno(如 errno = 0),以便后续检测
  3. 灵活进制:支持 2 到 36 之间的任意进制转换,若 base 为 0,则根据字符串前缀自动推断进制
  4. 推荐使用:相比 atol() 系列函数,strtoul() 更安全,支持错误检查和进制转换

3.5 示例程序

#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件才能使用 strtoul()
#include <errno.h>  // 包含 errno 和 ERANGE
#include <limits.h> // 包含 ULONG_MAXint 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 = 10printf("转换结果6: %lu, 结束位置: %s\n", result, endptr); // 输出: 转换结果6: 10, 结束位置: (null)// 示例 7:八进制转换result = strtoul("20", &endptr, 8);// 八进制 20 转换为十进制是 2*8^1 + 0*8^0 = 16 + 0 = 16printf("转换结果7: %lu, 结束位置: %s\n", result, endptr); // 输出: 转换结果7: 16, 结束位置: (null)// 示例 8:十六进制转换result = strtoul("FF", &endptr, 16);// 十六进制 FF 转换为十进制是 15*16^1 + 15*16^0 = 240 + 15 = 255printf("转换结果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_MAXunsigned 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)→ 八进制
        • 其他情况 → 十进制
  • 返回值:
    • 成功转换:返回对应的 unsigned long long int 值
    • 无效输入:若未执行任何转换,返回 0
    • 溢出情况:若转换结果超出 unsigned long long int 范围,返回 ULLONG_MAX,并设置 errno ERANGE

错误处理与范围检查相关概念:

  1. errno
    • 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码
    • 作用:当 strtoull() 等函数检测到错误(如数值溢出)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型
    • 使用建议:在调用 strtoull() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误
  2. ERANGE
    • 含义:ERANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)
    • 使用场景:当 strtoull() 检测到输入的字符串表示的数值超出 unsigned long long int 的表示范围(正数超过 ULLONG_MAX)时,会将 errno 设置为 ERANGE,表明发生了溢出错误
  3. ULLONG_MAX
    • 含义:ULLONG_MAX 是一个宏定义(定义在 <limits.h> 头文件中),表示 unsigned long long int 类型的最大值
    • 使用场景:若输入字符串表示的数值超出 unsigned long long int 的范围(正数超过 ULLONG_MAX),strtoull() 会返回 ULLONG_MAX 并设置 errno 为 ERANGE

4.3 转换规则

  1. 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等
  2. 识别正负号:
    1. 正号('+'):
      1. ​​​​​​​strtoull 允许在数字前添加正号('+'),但无符号整数(unsigned long long)无法表示负数,因此正号仅作为语法形式,对结果无实际影响
    2. 负号('-'):
      1. ​​​​​​​​​​​​​​strtoull 不支持负数(范围为 0 到 ULLONG_MAX)
      2. 标准行为:停止解析,endptr 指向负号位置('-'),返回 0
      3. 非标准行为:某些实现可能尝试解析负号后的数字,返回未定义值(可能是 0 或补码对应的随机值)
      4. 结论:不要依赖 strtoull 解析负数,否则会导致未定义行为
  3. 读取数字:根据指定的进制(base,范围为 2 到 36)解析数字字符
    1. 若 base 为 0,则自动推断进制
      1. 以 0x 或 0X 开头 → 十六进制
      2. 以 0 开头(且不是 0x 或 0X)→ 八进制
      3. 其他情况 → 十进制
  4. 停止转换:遇到第一个不符合当前进制规则的字符时停止解析,后续字符将被忽略
  5. 返回结果:将解析的数字转换为 unsigned long long int 类型返回
  6. 错误处理:
    1. 完全成功转换:
      1. endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证
      2. 示例:"12345678901234567890", NULL, 10 → 返回 12345678901234567890。
    2. 部分成功转换:
      1. endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证
      2. 示例:"12345678901234567890abc", NULL, 10 → 返回 12345678901234567890,endptr 指向 'a'。
    3. 无效输入:
      1. endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)
      2. 示例:"HelloWorld", NULL, 10 → 返回 0,endptr 指向 'H'。
    4. 溢出处理:需结合 errno 和 endptr 进行判断
      1. 正溢出:
        1. 返回 ULLONG_MAX,并设置 errno 为 ERANGE
        2. 示例:"18446744073709551616", NULL, 10 → 返回 ULLONG_MAX。

        转换示例:

输入字符串endptr 参数base返回值说明
"12345678901234567890"NULL1012345678901234567890完全成功转换
"-987654321"NULL10

返回 0(标准行为)或未定义值(取决于实现)

"    +12345678901234567890"NULL1012345678901234567890忽略前导空格后完全成功转换(正号无实际意义)
"12345678901234567890abc"NULL1012345678901234567890部分成功转换,endptr 指向 'a'
"HelloWorld"NULL100无效输入,endptr 指向 'H'
"1010"NULL210二进制转换
"20"NULL816八进制转换
"FF"NULL16255十六进制转换
"18446744073709551616"NULL10ULLONG_MAX正溢出

4.4 注意事项

  1. 错误检测:
    1. ​​​​​​​​​​​​​​方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败(即无效输入)
    2. 细节:
      1. 若 endptr == str:表示未解析出任何有效数字(如输入为 "Hello")
      2. 若 *endptr != '\0':表示部分成功转换(如输入为 "123abc",endptr 指向 'a')
      3. 若 *endptr == '\0':表示完全成功转换(如输入为 "123")
  2. 溢出处理:
    1. ​​​​​​​​​​​​​​条件:当输入的数值超出 unsigned long long int 的表示范围时,strtoull() 会设置 errno 为 ERANGE
    2. 行为:
      1. 正溢出:返回 ULLONG_MAX
    3. 建议:在调用 strtoull() 前,应清除 errno(如 errno = 0),以便后续检测
  3. 灵活进制:支持 2 到 36 之间的任意进制转换,若 base 为 0,则根据字符串前缀自动推断进制
  4. 推荐使用:相比 atoll() 系列函数,strtoull() 更安全,支持错误检查和进制转换

4.5 示例程序

#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件才能使用 strtoull()
#include <errno.h>  // 包含 errno 和 ERANGE
#include <limits.h> // 包含 ULLONG_MAXint 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 = 10printf("转换结果6: %llu, 结束位置: %s\n", result, endptr); // 输出: 转换结果6: 10, 结束位置: (null)// 示例 7:八进制转换result = strtoull("20", &endptr, 8);// 八进制 20 转换为十进制是 2*8^1 + 0*8^0 = 16 + 0 = 16printf("转换结果7: %llu, 结束位置: %s\n", result, endptr); // 输出: 转换结果7: 16, 结束位置: (null)// 示例 8:十六进制转换result = strtoull("FF", &endptr, 16);// 十六进制 FF 转换为十进制是 15*16^1 + 15*16^0 = 240 + 15 = 255printf("转换结果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)longLONG_MIN 到 LONG_MAX需要处理正负数的有符号整数转换无效输入时返回 0,溢出时返回 LONG_MIN 或 LONG_MAX,并设置 errno 为 ERANGE
strtoll将字符串转换为有符号长长整型(long long)long longLLONG_MIN 到 LLONG_MAX需要处理大范围有符号整数转换无效输入时返回 0,溢出时返回 LLONG_MIN 或 LLONG_MAX,并设置 errno 为 ERANGE
strtoul将字符串转换为无符号长整型(unsigned long)unsigned long0 到 ULONG_MAX需要处理非负数的无符号整数转换无效输入时返回 0,溢出时返回 ULONG_MAX,并设置 errno 为 ERANGE
strtoull将字符串转换为无符号长长整型(unsigned long long)unsigned long long0 到 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 的大小可能不同,因此在跨平台开发时需要注意数值范围的变化。

相关文章:

  • 硬盘寻址全解析:从 CHS 三维迷宫到 LBA 线性王国
  • Linux安全机制:从SELinux到Intel SGX的堡垒
  • Vue2 模板中使用可选链操作符(?.)的坑
  • Spring框架实现IOC
  • 【RTSP从零实践】1、根据RTSP协议实现一个RTSP服务
  • JavaScript篇:字母侦探:如何快速统计字符串里谁才是‘主角‘?
  • Improving Chinese Spelling Check by Character Pronunciation Prediction
  • 快速了解:单北斗终端的定义、作用与好处!
  • 基于ROS2,撰写python脚本,根据给定的舵-桨动力学模型实现动力学更新
  • RD-Agent-Quant:一个以数据为中心的因素与模型联合优化的多智能体框架
  • ROS2,工作空间中新建了一个python脚本,需要之后作为节点运行。告诉我步骤?
  • Vibe Coding AI编程
  • 管道与进程间通信
  • FreeRTOS事件组-笔记
  • 抖音怎么下载视频?抖音怎么无水印下载别人的视频
  • LeetCode 08.06 面试题 汉诺塔 (Java)
  • springBoot 通过模板导出Excel文档的实现
  • 第一章 计算机系统构成及硬件基础知识
  • 基于Java的离散数学题库系统设计与实现:附完整源码与论文
  • Web前端基础:JavaScript
  • nba新闻那个网站做的好/网络运营推广
  • 电子邮件网络营销方式/爱站网站长seo综合查询
  • 改wordpress登陆图标/网站怎么优化排名的方法
  • 汽车网站建设费用/郑州网络推广平台有哪些
  • 服务器网站建设维护合同/花西子网络营销案例分析
  • mindmanager网站建设流程图/百度搜索关键词查询