35 C 语言字符串转数值函数详解:strtof、strtod、strtold(含 errno 处理、ERANGE 错误)

1 strtof() 函数

1.1 函数原型

#include <stdlib.h> // 必须包含这个头文件才能使用 strtof()
#include <errno.h>  // 包含 errno 和 ERANGE
#include <float.h>  // 包含 FlOAT_MAX 和 FLOAT_MIN
#include <math.h>   // 包含 HUGE_VALF(inf)float strtof(const char *nptr, char **endptr);

1.2 功能说明

        strtof() 函数用于将字符串转换为单精度浮点数(float)。与 atof() 等函数相比,strtof() 提供了更灵活、安全的转换机制,支持完善的错误检查和转换结束位置定位。

  • 参数:
    • nptr:指向待转换的字符串(以空字符 \0 结尾)
    • endptr:用于存储转换结束位置的指针。如果不需要使用该信息,可以将其设置为 NULL
  • 返回值:
    • 成功转换:返回对应的 float 值
    • 无效输入:若未执行任何转换,返回 0.0f
    • 溢出情况:若转换结果超出 float 的表示范围
      • 正溢出:返回 HUGE_VALF(表示正无穷大,inf),并设置 errno ERANGE
      • 负溢出:返回 -HUGE_VALF(表示负无穷大,-inf),并设置 errno ERANGE
    • 下溢情况:若转换结果绝对值过小(小于 FLT_MIN),返回 0.0f,并设置 errno ERANGE(但某些实现可能不会设置 errno,具体行为取决于实现)

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

  1. errno
    • 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码
    • 作用:当 strtof() 等函数检测到错误(如数值溢出或下溢)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型
    • 使用建议:在调用 strtof() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误
  2. ERANGE
    • 含义:RANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)
    • 使用场景:当 strtof() 检测到输入的字符串表示的数值超出 float 的表示范围(过大或过小)时,会将 errno 设置为 ERANGE,表明发生了溢出或下溢错误
  3. HUGE_VALF
    • 含义:HUGE_VALF 是一个宏常量(定义在 <math.h> 头文件中),表示正无穷大(inf)的 float 值
    • 使用场景:当 strtof() 发生正溢出时,返回 HUGE_VALF(inf)
  4. FLT_MAX 和 FLT_MIN
    • 含义:FLT_MAX 和 FLT_MIN 是宏定义(定义在 <float.h> 头文件中),分别表示 float 类型的最大值和最小正规范化值
    • 使用场景:
      • 若输入字符串表示的数值超过 FLT_MAX,strtof() 会返回 HUGE_VALF(inf)并设置 errno 为 ERANGE
      • 若输入字符串表示的数值绝对值小于 FLT_MIN,strtof() 会返回 0.0f 并可能设置 errno 为 ERANGE(取决于实现)

1.3 转换规则

  1. 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等
  2. 识别正负号:支持在数字前添加可选的符号字符
    1. '+' 表示最终数值为正数
    2. '-' 表示最终数值为负数
    3. 若未指定符号,默认数值为正数
  3. 读取数字:解析字符串中的数字部分,支持以下格式
    1. 整数部分(如 "123")
    2. 小数部分(如 ".123" 或 "123.456")
    3. 指数部分(如 "1.23e4" 或 "1.23E-4")
  4. 停止转换:遇到第一个不符合浮点数规则的字符时停止解析,后续字符将被忽略
  5. 返回结果:将解析的数字转换为 float 类型返回
  6. 错误处理:
    1. 完全成功转换:
      1. endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证
      2. 示例:"3.1415926", NULL → 返回 3.141593。
    2. 部分成功转换:
      1. endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证
      2. 示例:"3.14abc", NULL → 返回 3.14,endptr 指向 'a'。
    3. 无效输入:
      1. endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)
      2. 示例:"HelloWorld", NULL → 返回 0.0f,endptr 指向 'H'。
    4. 溢出处理:需结合 errno 和 endptr 进行判断
      1. 正溢出:
        1. 返回 HUGE_VALF(表示正无穷大,inf),并设置 errno 为 ERANGE
        2. 示例:"1e50", NULL → 返回 HUGE_VALF。
      2. 负溢出:
        1. 返回 -HUGE_VALF(表示负无穷大,-inf),并设置 errno 为 ERANGE
        2. 示例:"-1e50", NULL → 返回 -HUGE_VALF。
      3. 下溢:
        1. 返回 0.0f,并可能设置 errno 为 ERANGE(具体行为取决于实现)
        2. 示例:"1e-50", NULL → 返回 0.0f。

        转换示例:

输入字符串endptr 参数返回值说明
"3.1415926"NULL3.141593f完全成功转换
"-2.71828"NULL-2.718280f完全成功转换(负数)
"    +123.456"NULL123.456000f忽略前导空格
"3.14abc"NULL3.140000f部分成功转换,endptr 指向 'a'
"HelloWorld"NULL0.000000f无效输入,endptr 指向 'H'
"1.23e4"NULL12300.000000f科学计数法转换
"1e50"NULLHUGE_VALF(inf)正溢出
"-1e50"NULL-HUGE_VALF(-inf)负溢出
"1e-50"NULL0.000000f下溢

1.4 注意事项

  1. 错误检测:
    1. 方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败
    2. 细节:
      1. 若 endptr == str:表示未解析出任何有效数字(如输入为 "HelloWorld")
      2. 若 *endptr != '\0':表示部分成功转换如输入为 "123.45abc",endptr 指向 'a')
      3. 若 *endptr == '\0':表示完全成功转换(如输入为 "123.45")
  2. 溢出处理:
    1. 条件:当输入的数值超出 float 的表示范围时,strtof() 会设置 errno 为 ERANGE
    2. 行为:
      1. 正溢出:返回 HUGE_VALF(inf)
      2. 负溢出:返回 -HUGE_VALF(-inf)
    3. 建议:在调用 strtof() 前,应清除 errno(如 errno = 0),以便后续检测
  3. 科学计数法支持:strtof() 支持科学计数法(如 "1.23e4" 或 "1.23E-4"),这是 atof() 等函数不具备的特性
  4. 推荐使用:相比 atof(),strtof() 更安全,支持错误检查和更灵活的浮点数格式解析

1.5 示例程序

#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件才能使用 strtof()
#include <errno.h>  // 包含 errno 和 ERANGE
#include <float.h>  // 包含 FlOAT_MAX 和 FLOAT_MIN
#include <math.h>   // 包含 HUGE_VALFint main()
{char *endptr; // 用于存储转换结束的位置float result; // 用于存储转换结果// 示例 1:基本转换result = strtof("3.1415926", &endptr);printf("转换结果1: %f, 结束位置: %s\n", result, endptr); // 输出: 转换结果1: 3.141593, 结束位置: (null)// 示例 2:带符号的数字result = strtof("-2.71828", &endptr);printf("转换结果2: %f, 结束位置: %s\n", result, endptr); // 输出: 转换结果2: -2.718280, 结束位置: (null)// 示例 3:带前导空格和符号result = strtof("    +123.456", &endptr);printf("转换结果3: %f, 结束位置: %s\n", result, endptr); // 输出: 转换结果3: 123.456000, 结束位置: (null)// 示例 4:部分有效的数字result = strtof("3.14abc", &endptr);printf("转换结果4: %f, 结束位置: %s\n", result, endptr); // 输出: 转换结果4: 3.140000, 结束位置: abc// 示例 5:无效输入result = strtof("HelloWorld", &endptr);printf("转换结果5: %f, 结束位置: %s\n", result, endptr); // 输出: 转换结果5: 0.000000, 结束位置: HelloWorld// 示例 6:科学计数法result = strtof("1.23e4", &endptr);printf("转换结果6: %f, 结束位置: %s\n", result, endptr); // 输出: 转换结果6: 12300.000000, 结束位置: (null)// 示例 7:正溢出检测errno = 0; // 重置 errno, 清除之前的错误result = strtof("1e50", &endptr);if (errno == ERANGE){printf("  errno = %d, ERANGE = %d\n", errno, ERANGE);             // 输出: errno = 34, ERANGE = 34printf("  HUGE_VALF: %f\n", HUGE_VALF);                           // 输出: HUGE_VALF: infprintf("  FLOAT_MAX: %e, FLOAT_MIN: %e\n", FLT_MAX, FLT_MIN);     // 输出: FLOAT_MAX: 3.402823e+38, FLOAT_MIN: 1.175494e-38printf("转换结果7: 超出范围,返回 HUGE_VALF(inf): %f\n", result); // 输出: 转换结果7: 超出范围,返回 HUGE_VALF(inf): inf}else{printf("转换结果7: %f\n", result);}// 示例 8:负溢出检测errno = 0; // 重置 errno, 清除之前的错误result = strtof("-1e50", &endptr);if (errno == ERANGE){printf("  errno = %d, ERANGE = %d\n", errno, ERANGE);               // 输出: errno = 34, ERANGE = 34printf("  -HUGE_VALF: %f\n", -HUGE_VALF);                           // 输出: -HUGE_VALF: -infprintf("  FLOAT_MAX: %e, FLOAT_MIN: %e\n", FLT_MAX, FLT_MIN);       // 输出: FLOAT_MAX: 3.402823e+38, FLOAT_MIN: 1.175494e-38printf("转换结果8: 超出范围,返回 -HUGE_VALF(-inf): %f\n", result); // 输出: 转换结果8: 超出范围,返回 -HUGE_VALF(-inf): -inf}else{printf("转换结果8: %f\n", result);}// 示例 9:下溢检测errno = 0; // 重置 errno, 清除之前的错误result = strtof("1e-50", &endptr);if (errno == ERANGE){printf("  errno = %d, ERANGE = %d\n", errno, ERANGE);                             // 输出: errno = 34, ERANGE = 34printf("  HUGE_VALF: %f, -HUGE_VALF: %f\n", HUGE_VALF, -HUGE_VALF);               // 输出: HUGE_VALF: inf, -HUGE_VALF: -infprintf("  FLOAT_MAX: %e, FLOAT_MIN: %e\n", FLT_MAX, FLT_MIN);                     // 输出: FLOAT_MAX: 3.402823e+38, FLOAT_MIN: 1.175494e-38printf("转换结果9: 字符串表示的数值绝对值小于 FLT_MIN,返回 0.0f: %f\n", result); // 输出: 转换结果9: 字符串表示的数值绝对值小于 FLT_MIN,返回 0.0f: 0.000000}else{printf("转换结果9: %f\n", result);}// 示例 10:检查转换是否完全成功result = strtof("123.456abc", &endptr);if (*endptr != '\0'){printf("转换结果10: %f, 但字符串未完全转换\n", result); // 输出: 转换结果10: 123.456000, 但字符串未完全转换}else{printf("转换结果10: %f\n", result);}return 0;
}

        程序在 VS Code 中的运行结果如下所示:


2 strtod() 函数

2.1 函数原型

#include <stdlib.h> // 必须包含这个头文件才能使用 strtod()
#include <errno.h>  // 包含 errno 和 ERANGE
#include <float.h>  // 包含 DBL_MAX 和 DBL_MIN
#include <math.h>   // 包含 HUGE_VALdouble strtod(const char *nptr, char **endptr);

2.2 功能说明

        strtod() 函数用于将字符串转换为双精度浮点数(double)。与 atof() 等函数相比,strtod() 提供了更灵活、安全的转换机制,支持完善的错误检查和转换结束位置定位。

  • 参数:
    • nptr:指向待转换的字符串(以空字符 \0 结尾)
    • endptr:用于存储转换结束位置的指针。如果不需要使用该信息,可以将其设置为 NULL
  • 返回值:
    • 成功转换:返回对应的 double 值
    • 无效输入:若未执行任何转换,返回 0.0
    • 溢出情况:若转换结果超出 double 的表示范围
      • 正溢出:返回 HUGE_VAL(表示正无穷大,inf),并设置 errno ERANGE
      • 负溢出:返回 -HUGE_VAL(表示负无穷大,-inf),并设置 errno ERANGE
    • 下溢情况:若转换结果绝对值过小(小于 DBL_MIN),返回 0.0,并设置 errno ERANGE(但某些实现可能不会设置 errno,具体行为取决于实现)

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

  1. errno
    • 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码
    • 作用:当 strtod() 等函数检测到错误(如数值溢出或下溢)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型
    • 使用建议:在调用 strtod() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误
  2. ERANGE
    • 含义:RANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)
    • 使用场景:当 strtod() 检测到输入的字符串表示的数值超出 double 的表示范围(过大或过小)时,会将 errno 设置为 ERANGE,表明发生了溢出或下溢错误
  3. HUGE_VAL
    • 含义:HUGE_VAL 是一个宏常量(定义在 <math.h> 头文件中),表示正无穷大(inf)的 double 值
    • 使用场景:当 strtod() 发生正溢出时,返回 HUGE_VAL(inf)
  4. DBL_MAX 和 DBL_MIN
    • 含义:DBL_MAX 和 DBL_MIN 是宏定义(定义在 <float.h> 头文件中),分别表示 double 类型的最大值和最小正规范化值
    • 使用场景:
      • 若输入字符串表示的数值超过 DBL_MAX,strtod() 会返回 HUGE_VAL(inf)并设置 errno 为 ERANGE
      • 若输入字符串表示的数值绝对值小于 DBL_MIN,strtod() 会返回 0.0 并可能设置 errno 为 ERANGE(取决于实现)

2.3 转换规则

  1. 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等
  2. 识别正负号:支持在数字前添加可选的符号字符
    1. '+' 表示最终数值为正数
    2. '-' 表示最终数值为负数
    3. 若未指定符号,默认数值为正数
  3. 读取数字:解析字符串中的数字部分,支持以下格式
    1. 整数部分(如 "123")
    2. 小数部分(如 ".123" 或 "123.456")
    3. 指数部分(如 "1.23e4" 或 "1.23E-4")
  4. 停止转换:遇到第一个不符合浮点数规则的字符时停止解析,后续字符将被忽略
  5. 返回结果:将解析的数字转换为 double 类型返回
  6. 错误处理:
    1. 完全成功转换:
      1. endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证
      2. 示例:"3.1415926", NULL → 返回 3.141593。
    2. 部分成功转换:
      1. endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证
      2. 示例:"3.14abc", NULL → 返回 3.14,endptr 指向 'a'。
    3. 无效输入:
      1. endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)
      2. 示例:"HelloWorld", NULL → 返回 0.0f,endptr 指向 'H'。
    4. 溢出处理:需结合 errno 和 endptr 进行判断
      1. 正溢出:
        1. 返回 HUGE_VAL(表示正无穷大,inf),并设置 errno 为 ERANGE
        2. 示例:"1e500", NULL → 返回 HUGE_VAL。
      2. 负溢出:
        1. 返回 -HUGE_VAL(表示负无穷大,-inf),并设置 errno 为 ERANGE
        2. 示例:"-1e500", NULL → 返回 -HUGE_VAL。
      3. 下溢:
        1. 返回 0.0,并可能设置 errno 为 ERANGE(具体行为取决于实现)
        2. 示例:"1e-500", NULL → 返回 0.0。

        转换示例:

输入字符串endptr 参数返回值说明
"3.1415926"NULL3.141593完全成功转换
"-2.71828"NULL-2.718280完全成功转换(负数)
"    +123.456"NULL123.456000忽略前导空格
"3.14abc"NULL3.140000部分成功转换,endptr 指向 'a'
"HelloWorld"NULL0.000000无效输入,endptr 指向 'H'
"1.23e4"NULL12300.000000科学计数法转换
"1e500"NULLHUGE_VAL(inf)正溢出
"-1e500"NULL-HUGE_VAL(-inf)负溢出
"1e-500"NULL0.000000下溢

2.4 注意事项

  1. 错误检测:
    1. 方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败
    2. 细节:
      1. 若 endptr == str:表示未解析出任何有效数字(如输入为 "HelloWorld")
      2. 若 *endptr != '\0':表示部分成功转换如输入为 "123.45abc",endptr 指向 'a')
      3. 若 *endptr == '\0':表示完全成功转换(如输入为 "123.45")
  2. 溢出处理:
    1. 条件:当输入的数值超出 double 的表示范围时,strtod() 会设置 errno 为 ERANGE
    2. 行为:
      1. 正溢出:返回 HUGE_VAL(inf)
      2. 负溢出:返回 -HUGE_VAL(-inf)
    3. 建议:在调用 strtod() 前,应清除 errno(如 errno = 0),以便后续检测
  3. 科学计数法支持:strtod() 支持科学计数法(如 "1.23e4" 或 "1.23E-4"),这是 atof() 等函数不具备的特性
  4. 推荐使用:相比 atof(),strtod() 更安全,支持错误检查和更灵活的浮点数格式解析

2.5 示例程序

#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件才能使用 strtod()
#include <errno.h>  // 包含 errno 和 ERANGE
#include <float.h>  // 包含 DBL_MAX 和 DBL_MIN
#include <math.h>   // 包含 HUGE_VALint main()
{char *endptr;  // 用于存储转换结束的位置double result; // 用于存储转换结果(改为 double 类型)// 示例 1:基本转换result = strtod("3.1415926", &endptr);printf("转换结果1: %lf, 结束位置: %s\n", result, endptr); // 输出: 转换结果1: 3.141593, 结束位置: (null)// 示例 2:带符号的数字result = strtod("-2.71828", &endptr);printf("转换结果2: %lf, 结束位置: %s\n", result, endptr); // 输出: 转换结果2: -2.718280, 结束位置: (null)// 示例 3:带前导空格和符号result = strtod("    +123.456", &endptr);printf("转换结果3: %lf, 结束位置: %s\n", result, endptr); // 输出: 转换结果3: 123.456001, 结束位置: (null)// 示例 4:部分有效的数字result = strtod("3.14abc", &endptr);printf("转换结果4: %lf, 结束位置: %s\n", result, endptr); // 输出: 转换结果4: 3.140000, 结束位置: abc// 示例 5:无效输入result = strtod("HelloWorld", &endptr);printf("转换结果5: %lf, 结束位置: %s\n", result, endptr); // 输出: 转换结果5: 0.000000, 结束位置: HelloWorld// 示例 6:科学计数法result = strtod("1.23e4", &endptr);printf("转换结果6: %lf, 结束位置: %s\n", result, endptr); // 输出: 转换结果6: 12300.000000, 结束位置: (null)// 示例 7:正溢出检测errno = 0; // 重置 errno, 清除之前的错误result = strtod("1e500", &endptr);if (errno == ERANGE){printf("  errno = %d, ERANGE = %d\n", errno, ERANGE);             // 输出: errno = 34, ERANGE = 34printf("  HUGE_VAL: %lf\n", HUGE_VAL);                            // 输出: HUGE_VAL: infprintf("  DBL_MAX: %e, DBL_MIN: %e\n", DBL_MAX, DBL_MIN);         // 输出: DBL_MAX: 1.797693e+308, DBL_MIN: 2.225074e-308printf("转换结果7: 超出范围,返回 HUGE_VAL(inf): %lf\n", result); // 输出: 转换结果7: 超出范围,返回 HUGE_VAL(inf): inf}else{printf("转换结果7: %lf\n", result);}// 示例 8:负溢出检测errno = 0; // 重置 errno, 清除之前的错误result = strtod("-1e500", &endptr);if (errno == ERANGE){printf("  errno = %d, ERANGE = %d\n", errno, ERANGE);               // 输出: errno = 34, ERANGE = 34printf("  -HUGE_VAL: %lf\n", -HUGE_VAL);                            // 输出: -HUGE_VAL: -infprintf("  DBL_MAX: %e, DBL_MIN: %e\n", DBL_MAX, DBL_MIN);           // 输出: DBL_MAX: 1.797693e+308, DBL_MIN: 2.225074e-308printf("转换结果8: 超出范围,返回 -HUGE_VAL(-inf): %lf\n", result); // 输出: 转换结果8: 超出范围,返回 -HUGE_VAL(-inf): -inf}else{printf("转换结果8: %lf\n", result);}// 示例 9:下溢检测errno = 0; // 重置 errno, 清除之前的错误result = strtod("1e-500", &endptr);if (errno == ERANGE){printf("  errno = %d, ERANGE = %d\n", errno, ERANGE);                            // 输出: errno = 34, ERANGE = 34printf("  HUGE_VALF: %f, -HUGE_VALF: %f\n", HUGE_VALF, -HUGE_VALF);              // 输出: HUGE_VALF: inf, -HUGE_VALF: -infprintf("  DBL_MAX: %e, DBL_MIN: %e\n", DBL_MAX, DBL_MIN);                        // 输出: DBL_MAX: 1.797693e+308, DBL_MIN: 2.225074e-308printf("转换结果9: 字符串表示的数值绝对值小于 DBL_MIN,返回 0.0: %f\n", result); // 输出: 转换结果9: 字符串表示的数值绝对值小于 DBL_MIN,返回 0.0: 0.000000}else{printf("转换结果9: %lf\n", result);}// 示例 10:检查转换是否完全成功result = strtod("123.45abc", &endptr);if (*endptr != '\0'){printf("转换结果10: %lf, 但字符串未完全转换\n", result); // 输出: 转换结果10: 123.450000, 但字符串未完全转换}else{printf("转换结果10: %lf\n", result);}return 0;
}

        程序在 VS Code 中的运行结果如下所示:


3 strtold() 函数

3.1 函数原型

#include <stdlib.h> // 必须包含这个头文件才能使用 strtold()
#include <errno.h>  // 包含 errno 和 ERANGE
#include <float.h>  // 包含 LDBL_MAX 和 LDBL_MIN
#include <math.h>   // 包含 HUGE_VALLlong double strtold(const char *nptr, char **endptr);

3.2 功能说明

        strtold() 函数用于将字符串转换为长双精度浮点数(long double)。与 atof() 等函数相比,strtold() 提供了更灵活、安全的转换机制,支持完善的错误检查和转换结束位置定位。

  • 参数:
    • nptr:指向待转换的字符串(以空字符 \0 结尾)
    • endptr:用于存储转换结束位置的指针。如果不需要使用该信息,可以将其设置为 NULL
  • 返回值:
    • 成功转换:返回对应的 long double 值
    • 无效输入:若未执行任何转换,返回 0.0L
    • 溢出情况:若转换结果超出 long double 的表示范围
      • 正溢出:返回 HUGE_VALL(表示正无穷大,inf),并设置 errno ERANGE
      • 负溢出:返回 -HUGE_VALL(表示负无穷大,-inf),并设置 errno ERANGE
    • 下溢情况:若转换结果绝对值过小(小于 LDBL_MIN),返回 0.0L,并设置 errno ERANGE(但某些实现可能不会设置 errno,具体行为取决于实现)

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

  1. errno
    • 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码
    • 作用:当 strtold() 等函数检测到错误(如数值溢出或下溢)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型
    • 使用建议:在调用 strtold() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误
  2. ERANGE
    • 含义:RANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)
    • 使用场景:当 strtold() 检测到输入的字符串表示的数值超出 long double 的表示范围(过大或过小)时,会将 errno 设置为 ERANGE,表明发生了溢出或下溢错误
  3. HUGE_VALL
    • 含义:HUGE_VALL 是一个宏常量(定义在 <math.h> 头文件中),表示正无穷大(inf)的 long double 值
    • 使用场景:当 strtold() 发生正溢出时,返回 HUGE_VALL(inf)
  4. LDBL_MAX 和 LDBL_MIN
    • 含义:LDBL_MAX 和 LDBL_MIN 是宏定义(定义在 <float.h> 头文件中),分别表示 long double 类型的最大值和最小正规范化值
    • 使用场景:
      • 若输入字符串表示的数值超过 LDBL_MAX,strtold() 会返回 HUGE_VALL(inf)并设置 errno 为 ERANGE
      • 若输入字符串表示的数值绝对值小于 LDBL_MIN,strtold() 会返回 0.0L 并可能设置 errno 为 ERANGE(取决于实现)

3.3 转换规则

  1. 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等
  2. 识别正负号:支持在数字前添加可选的符号字符
    1. '+' 表示最终数值为正数
    2. '-' 表示最终数值为负数
    3. 若未指定符号,默认数值为正数
  3. 读取数字:解析字符串中的数字部分,支持以下格式
    1. 整数部分(如 "123")
    2. 小数部分(如 ".123" 或 "123.456")
    3. 指数部分(如 "1.23e4" 或 "1.23E-4")
  4. 停止转换:遇到第一个不符合浮点数规则的字符时停止解析,后续字符将被忽略
  5. 返回结果:将解析的数字转换为 long double 类型返回
  6. 错误处理:
    1. 完全成功转换:
      1. endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证
      2. 示例:"3.1415926535", NULL → 返回 3.141593。
    2. 部分成功转换:
      1. endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证
      2. 示例:"3.14abc", NULL → 返回 3.14,endptr 指向 'a'。
    3. 无效输入:
      1. endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)
      2. 示例:"HelloWorld", NULL → 返回 0.0f,endptr 指向 'H'。
    4. 溢出处理:需结合 errno 和 endptr 进行判断
      1. 正溢出:
        1. 返回 HUGE_VALL(表示正无穷大,inf),并设置 errno 为 ERANGE
        2. 示例:"1e5000", NULL → 返回 HUGE_VALL。
      2. 负溢出:
        1. 返回 -HUGE_VALL(表示负无穷大,-inf),并设置 errno 为 ERANGE
        2. 示例:"-1e5000", NULL → 返回 -HUGE_VALL。
      3. 下溢:
        1. 返回 0.0f,并可能设置 errno 为 ERANGE(具体行为取决于实现)
        2. 示例:"1e-5000", NULL → 返回 0.0L。

        转换示例:

输入字符串endptr 参数返回值说明
"3.1415926535"NULL3.141593L完全成功转换
"-2.718281828"NULL-2.718282L完全成功转换(负数)
"    +123.456"NULL123.456000L忽略前导空格
"3.14abc"NULL3.140000L部分成功转换,endptr 指向 'a'
"HelloWorld"NULL0.000000L无效输入,endptr 指向 'H'
"1.23e4"NULL12300.000000L科学计数法转换
"1e5000"NULLHUGE_VALL(inf)正溢出
"-1e5000"NULL-HUGE_VALL(-inf)负溢出
"1e-5000"NULL0.000000L下溢

3.4 注意事项

  1. 错误检测:
    1. 方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败
    2. 细节:
      1. 若 endptr == str:表示未解析出任何有效数字(如输入为 "HelloWorld")
      2. 若 *endptr != '\0':表示部分成功转换如输入为 "123.45abc",endptr 指向 'a')
      3. 若 *endptr == '\0':表示完全成功转换(如输入为 "123.45")
  2. 溢出处理:
    1. 条件:当输入的数值超出 long double 的表示范围时,strtold() 会设置 errno 为 ERANGE
    2. 行为:
      1. 正溢出:返回 HUGE_VALL(inf)
      2. 负溢出:返回 -HUGE_VALL(-inf)
    3. 建议:在调用 strtold() 前,应清除 errno(如 errno = 0),以便后续检测
  3. 科学计数法支持:strtold() 支持科学计数法(如 "1.23e4" 或 "1.23E-4"),这是 atof() 等函数不具备的特性
  4. 推荐使用:相比 atof(),strtold() 更安全,支持错误检查和更灵活的浮点数格式解析

3.5 示例程序

#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件才能使用 strtold()
#include <errno.h>  // 包含 errno 和 ERANGE
#include <float.h>  // 包含 LDBL_MAX 和 LDBL_MIN
#include <math.h>   // 包含 HUGE_VALLint main()
{char *endptr;       // 用于存储转换结束的位置long double result; // 用于存储转换结果(改为 long double 类型)// 示例 1:基本转换result = strtold("3.1415926535", &endptr);printf("转换结果1: %Lf, 结束位置: %s\n", result, endptr); // 输出: 转换结果1: 3.141593, 结束位置: (null)// 示例 2:带符号的数字result = strtold("-2.718281828", &endptr);printf("转换结果2: %Lf, 结束位置: %s\n", result, endptr); // 输出: 转换结果2: -2.718282, 结束位置: (null)// 示例 3:带前导空格和符号result = strtold("    +123.456", &endptr);printf("转换结果3: %Lf, 结束位置: %s\n", result, endptr); // 输出: 转换结果3: 123.456000, 结束位置: (null)// 示例 4:部分有效的数字result = strtold("3.14abc", &endptr);printf("转换结果4: %Lf, 结束位置: %s\n", result, endptr); // 输出: 转换结果4: 3.140000, 结束位置: abc// 示例 5:无效输入result = strtold("HelloWorld", &endptr);printf("转换结果5: %Lf, 结束位置: %s\n", result, endptr); // 输出: 转换结果5: 0.000000, 结束位置: HelloWorld// 示例 6:科学计数法result = strtold("1.23e4", &endptr);printf("转换结果6: %Lf, 结束位置: %s\n", result, endptr); // 输出: 转换结果6: 12300.000000, 结束位置: (null)// 示例 7:正溢出检测errno = 0; // 重置 errno, 清除之前的错误result = strtold("1e5000", &endptr);if (errno == ERANGE){printf("  errno = %d, ERANGE = %d\n", errno, ERANGE);              // 输出: errno = 34, ERANGE = 34printf("  HUGE_VALL: %Lf\n", HUGE_VALL);                           // 输出: HUGE_VALL: infprintf("  LDBL_MAX: %Le, LDBL_MIN: %Le\n", LDBL_MAX, LDBL_MIN);    // 输出: LDBL_MAX: 1.189731e+4932, LDBL_MIN: 3.362103e-4932printf("转换结果7: 超出范围,返回 HUGE_VALL(inf): %Lf\n", result); // 输出: 转换结果7: 超出范围,返回 HUGE_VALL(inf): inf}else{printf("转换结果7: %Lf\n", result);}// 示例 8:负溢出检测errno = 0; // 重置 errno, 清除之前的错误result = strtold("-1e5000", &endptr);if (errno == ERANGE){printf("  errno = %d, ERANGE = %d\n", errno, ERANGE);                // 输出: errno = 34, ERANGE = 34printf("  -HUGE_VALL: %Lf\n", -HUGE_VALL);                           // 输出: -HUGE_VALL: -infprintf("  LDBL_MAX: %Le, LDBL_MIN: %Le\n", LDBL_MAX, LDBL_MIN);      // 输出: LDBL_MAX: 1.189731e+4932, LDBL_MIN: 3.362103e-4932printf("转换结果8: 超出范围,返回 -HUGE_VALL(-inf): %Lf\n", result); // 输出: 转换结果8: 超出范围,返回 -HUGE_VALL(-inf): -inf}else{printf("转换结果8: %Lf\n", result);}// 示例 9:下溢检测errno = 0; // 重置 errno, 清除之前的错误result = strtold("1e-5000", &endptr);if (errno == ERANGE){printf("  errno = %d, ERANGE = %d\n", errno, ERANGE);                               // 输出: errno = 34, ERANGE = 34printf("  HUGE_VALF: %f, -HUGE_VALF: %f\n", HUGE_VALF, -HUGE_VALF);                 // 输出: HUGE_VALF: inf, -HUGE_VALF: -infprintf("  LDBL_MAX: %Le, LDBL_MIN: %Le\n", LDBL_MAX, LDBL_MIN);                     // 输出: LDBL_MAX: 1.189731e+4932, LDBL_MIN: 3.362103e-4932printf("转换结果9: 字符串表示的数值绝对值小于 LDBL_MIN,返回 0.0L: %Lf\n", result); // 输出: 转换结果9: 字符串表示的数值绝对值小于 LDBL_MIN,返回 0.0L: 0.000000}else{printf("转换结果9: %Lf\n", result);}// 示例 10:检查转换是否完全成功result = strtold("123.45abc", &endptr);if (*endptr != '\0'){printf("转换结果10: %Lf, 但字符串未完全转换\n", result); // 输出: 转换结果10: 123.450000, 但字符串未完全转换}else{printf("转换结果9: %Lf\n", result);}return 0;
}

        程序在 VS Code 中的运行结果如下所示:


4 字符串转数值函数总结

函数名功能返回值类型转换范围适用场景错误处理(errno)
strtof将字符串转换为单精度浮点型(float)floatFLT_MIN 到 FLT_MAX(通常为 1.175494e-38 到 3.402823e+38)需要处理单精度浮点数的转换

无效输入时返回 0.0f;

正溢出时返回 +HUGE_VALF(inf);

负溢出时返回 -HUGE_VALF(-inf);

下溢时可能返回 0.0f 或次正规数(取决于实现),并设置 errno 为 ERANGE(仅溢出时设置)

strtod将字符串转换为双精度浮点型(double)doubleDBL_MIN 到 DBL_MAX(通常为 2.225074e-308 到 1.797693e+308)需要处理双精度浮点数的转换

无效输入时返回 0.0;

正溢出时返回 +HUGE_VAL(inf);

负溢出时返回 -HUGE_VAL(-inf);

下溢时可能返回 0.0 或次正规数(取决于实现),并设置 errno 为 ERANGE(仅溢出时设置)

strtold将字符串转换为扩展精度浮点型(long double)long doubleLDBL_MIN 到 LDBL_MAX(范围因平台而异,通常更大)需要处理高精度或大范围浮点数的转换

无效输入时返回 0.0L;

正溢出时返回 +HUGE_VALL(inf);

负溢出时返回 -HUGE_VALL(-inf);

下溢时可能返回 0.0L 或次正规数(取决于实现),并设置 errno 为 ERANGE(仅溢出时设置)

  • 头文件:所有这些函数都定义在 <stdlib.h> 头文件中,使用时需要包含该头文件。

  • 错误处理细节:

    • 当转换结果超出目标类型的最大正值时,函数返回 +HUGE_VALF、+HUGE_VAL 或 +HUGE_VALL(取决于函数类型),并设置 errno 为 ERANGE
    • 当转换结果小于目标类型的最小负值时,函数返回 -HUGE_VALF、-HUGE_VAL 或 -HUGE_VALL(取决于函数类型),并设置 errno 为 ERANGE
    • 当转换结果非常接近零,但仍在目标类型的范围内时,函数可能返回 0.0、0.0f、0.0L 或一个次正规数(即一个非常小的非零值,其精度可能低于正常范围的数值)。下溢通常不会设置 errno 为 ERANGE,除非在某些特定实现中明确规定
  • 跨平台兼容性:

    • 这些函数是 C 标准库的一部分,因此在大多数平台上都可用。
    • 浮点类型的范围(如 FLT_MAX、DBL_MAX、LDBL_MAX)和精度(如 FLT_DIG、DBL_DIG、LDBL_DIG)可能因平台和编译器实现而异,因此在跨平台开发时需要注意这些差异。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/84072.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PaddleOCR项目实战(1):Python脚本中使⽤PaddleOCR

1 项目介绍 项目架构如下&#xff1a; APP/WEB/⼩程序为OCR识别接⼝调⽤端&#xff0c;调⽤OCR接⼝&#xff0c;实现OCR功能。本项⽬我们只实现Android APP开发。Nginx反向代理和负载均衡功能&#xff0c;通过Nginx实现对外⽹暴露接⼝&#xff0c;对内负载均衡SpringBoot实现的…

Reranker + BM25 + FAISS 构建高效的多阶段知识库检索系统一

一、什么是知识库检索&#xff1f; 在构建基于大语言模型的问答系统&#xff08;如 RAG&#xff09;中&#xff0c;知识库检索&#xff08;Retrieval&#xff09; 是第一步&#xff0c;也是影响最终回答质量的关键环节。它负责从大规模文档中快速定位与用户问题最相关的 top-k…

Walle-Web:打造轻量级高效的DevOps自动化部署平台

在当今快速迭代的开发环境中,高效的代码部署工具已成为团队不可或缺的基础设施。Walle-Web作为一款免费开源的DevOps平台,专注解决"部署难、管理乱"的痛点问题,为开发团队提供了简洁而强大的自动化部署解决方案。 1. 什么是Walle-Web? Walle-Web是一款专注于代码…

力扣LeetBook数组和字符串--二维数组

1.旋转矩阵 题目链接 想了那么久的各种旋转&#xff0c;对角线&#xff0c;其实把问题搞复杂了。 旋转90度的本质无非就是转置镜像对称 转置是什么&#xff1f;&#xff1a;将矩阵的行和列互换。 镜像对称&#xff1a;把矩阵从中间对折&#xff0c;互换位置 矩阵 A A [ 1 3 0…

图论水题2

div2 361 D. Tree Requests 题意 对于一颗 n n n节点的树&#xff0c;每个节点有一个字母&#xff0c;有 m m m次询问&#xff0c;每次询问求对于顶点 v v v的子树中深度为 h h h的结点能否组成一个回文串$ (1 \leq n \leq m \leq 5 \cdot 10^5) $ 思路 关于 v v v的子树结…

Redis 过期了解

Redis 版本&#xff1a;5.0 &#xff1a; 一&#xff1a;过期监听&#xff1a; Spring Data Redis 封装了 Redis 的 Pub/Sub 功能&#xff0c;提供了对 key 过期事件的监听支持。 1. 核心类&#xff1a;KeyExpirationEventMessageListener 这个抽象类是 Spring 提供的&#x…

OA工程自动化办公系统 – 免费Java源码

概述 功能完备的OA工程自动化办公系统Java源码&#xff0c;采用主流技术栈开发&#xff0c;无论是学习SpringBoot框架还是开发企业级应用&#xff0c;都是不可多得的优质资源。 主要内容 技术架构 ​​后端技术栈​​&#xff1a; 核心框架&#xff1a;SpringBoot 2.xORM框…

嵌入式SDK技术EasyRTC音视频实时通话助力即时通信社交/教育等多场景创新应用

一、引言​ 在数字化时代&#xff0c;即时通信已成为人们生活和工作中不可或缺的部分。音视频功能作为即时通信的核心&#xff0c;能实现更加直观、高效的信息传递。EasyRTC作为一款强大的实时通信框架&#xff0c;具备诸多优势&#xff0c;为即时通信的音视频应用提供了优质解…

BEV和OCC学习-5:数据预处理流程

参考&#xff1a;自定义数据预处理流程 — MMDetection3D 1.4.0 文档 数据预处理流程的设计 预处理流程中的各项操作主要分为数据加载、预处理、格式化、测试时的数据增强。 接下来将展示一个用于 PointPillars 模型的数据集预处理流程的例子。 train_pipeline [dict(type…

OGG 23ai for DAA 部署与补丁升级

创建ogg 用户 /usr/sbin/groupadd -g 1002 dba /usr/sbin/groupadd -g 1001 oinstall /usr/sbin/groupadd -g 1003 oper useradd -u 1001 -g oinstall -G dba,oper oracle echo "oracle" |passwd oracle --stdin创建ogg安装目录 mkdir -p /u01/app/ogg/soft mkdir …

【LangchainAgent】Agent基本构建与使用

目录 一、功能简述 代码功能概括 &#x1f3af; 核心能力 二、运作流程 三、核心代码 四、运行结果 五、代码功能拆解 ✅ 1. 环境准备与依赖导入 ✅ 2. 加载网页文档并处理为向量 ✅ 3. 创建检索工具与搜索工具 ✅ 4. 初始化语言模型与 Agent ✅ 5. 封装支持多轮记…

【云安全】以Aliyun为例聊云厂商服务常见利用手段

目录 OSS-bucket_policy_readable OSS-object_public_access OSS-bucket_object_traversal OSS-Special Bucket Policy OSS-unrestricted_file_upload OSS-object_acl_writable ECS-SSRF 云攻防场景下对云厂商服务的利用大同小异&#xff0c;下面以阿里云为例 其他如腾…

完成一个可交互的k8s管理平台的页面开发

使用deepseek完成设计一个k8s管理平台&#xff0c;关键词如下&#xff1a; 完成一个可交互的k8s管理平台的页面开发Kubernetes 管理平台页面设计 下面是一个基于现代Web技术的可交互Kubernetes管理平台的页面设计方案&#xff0c;使用React作为前端框架&#xff0c;配合Ant De…

TDengine 支持的平台汇总

TDengine 服务端支持的平台列表 注&#xff1a;1) ● 表示经过官方测试验证&#xff0c; ○ 表示非官方测试验证&#xff0c;E 表示仅企业版支持。 2) 社区版仅支持主流操作系统的较新版本&#xff0c;包括 Ubuntu 18/CentOS 7/CentOS Stream/RedHat/Debian/CoreOS/FreeBSD/Op…

使用 HTML + JavaScript 实现文章逐句高亮朗读功能

在这个信息爆炸的时代&#xff0c;我们每天都要面对大量的文字阅读。无论是学习、工作还是个人成长&#xff0c;阅读都扮演着至关重要的角色。然而&#xff0c;在快节奏的生活中&#xff0c;我们往往难以找到足够的安静时间专注于阅读。本文用 HTML JavaScript 实现了一个基于…

理解非结构化文档:将 Reducto 解析与 Elasticsearch 结合使用

作者&#xff1a;来自 Elastic Adel Wu 演示如何将 Reducto 的文档处理与 Elasticsearch 集成以实现语义搜索。 Elasticsearch 与业界领先的生成式 AI 工具和提供商有原生集成。欢迎观看我们的网络研讨会&#xff0c;了解如何超越 RAG 基础&#xff0c;或使用 Elastic 向量数据…

从Copilot到Agent,AI Coding是如何进化的?

编程原本是一项具有一定门槛的技能&#xff0c;但借助 AI Coding 产品&#xff0c;新手也能写出可运行的代码&#xff0c;非专业人员如业务分析师、产品经理&#xff0c;也能在 AI 帮助下直接生成简单应用。 这一演变对软件产业产生了深远影响。当 AI 逐步参与代码生成、调试乃…

UGUI Text/TextMeshPro字体组件

UGUI Text组件的不当使用及其性能瓶颈与优化 在Unity UGUI系统中&#xff0c;Text 组件&#xff08;或其升级版 TextMeshPro&#xff09;是显示文本信息的核心元素。然而&#xff0c;如果不当使用&#xff0c;它极易成为UI性能瓶颈的罪魁祸首&#xff0c;尤其是在预制体、属性…

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…

【个人笔记】数据库原理(西电)

写在前面&#xff1a;文中提到的页面指向&#xff08;如“p45”&#xff09;&#xff0c;除特别说明&#xff0c;都是指对应ppt上的页面&#xff0c;非同款ppt的友友可忽略 第一章 ER图和关系分解见课本p69 ER图是常用的 概念模型 方形&#xff1a;实体圆形&#xff1a;属性…