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,具体行为取决于实现)。
错误处理与范围检查相关概念:
- errno
- 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码。
- 作用:当 strtof() 等函数检测到错误(如数值溢出或下溢)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型。
- 使用建议:在调用 strtof() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误。
- ERANGE
- 含义:RANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)。
- 使用场景:当 strtof() 检测到输入的字符串表示的数值超出 float 的表示范围(过大或过小)时,会将 errno 设置为 ERANGE,表明发生了溢出或下溢错误。
- HUGE_VALF
- 含义:HUGE_VALF 是一个宏常量(定义在 <math.h> 头文件中),表示正无穷大(inf)的 float 值。
- 使用场景:当 strtof() 发生正溢出时,返回 HUGE_VALF(inf)。
- 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 转换规则
- 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等。
- 识别正负号:支持在数字前添加可选的符号字符:
- '+' 表示最终数值为正数。
- '-' 表示最终数值为负数。
- 若未指定符号,默认数值为正数。
- 读取数字:解析字符串中的数字部分,支持以下格式:
- 整数部分(如 "123")。
- 小数部分(如 ".123" 或 "123.456")。
- 指数部分(如 "1.23e4" 或 "1.23E-4")。
- 停止转换:遇到第一个不符合浮点数规则的字符时停止解析,后续字符将被忽略。
- 返回结果:将解析的数字转换为 float 类型返回。
- 错误处理:
- 完全成功转换:
- endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证。
- 示例:"3.1415926", NULL → 返回 3.141593。
- 部分成功转换:
- endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证。
- 示例:"3.14abc", NULL → 返回 3.14,endptr 指向 'a'。
- 无效输入:
- endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)。
- 示例:"HelloWorld", NULL → 返回 0.0f,endptr 指向 'H'。
- 溢出处理:需结合 errno 和 endptr 进行判断。
- 正溢出:
- 返回 HUGE_VALF(表示正无穷大,inf),并设置 errno 为 ERANGE。
- 示例:"1e50", NULL → 返回 HUGE_VALF。
- 负溢出:
- 返回 -HUGE_VALF(表示负无穷大,-inf),并设置 errno 为 ERANGE。
- 示例:"-1e50", NULL → 返回 -HUGE_VALF。
- 下溢:
- 返回 0.0f,并可能设置 errno 为 ERANGE(具体行为取决于实现)。
- 示例:"1e-50", NULL → 返回 0.0f。
- 正溢出:
- 完全成功转换:
转换示例:
输入字符串 | endptr 参数 | 返回值 | 说明 |
---|---|---|---|
"3.1415926" | NULL | 3.141593f | 完全成功转换 |
"-2.71828" | NULL | -2.718280f | 完全成功转换(负数) |
" +123.456" | NULL | 123.456000f | 忽略前导空格 |
"3.14abc" | NULL | 3.140000f | 部分成功转换,endptr 指向 'a' |
"HelloWorld" | NULL | 0.000000f | 无效输入,endptr 指向 'H' |
"1.23e4" | NULL | 12300.000000f | 科学计数法转换 |
"1e50" | NULL | HUGE_VALF(inf) | 正溢出 |
"-1e50" | NULL | -HUGE_VALF(-inf) | 负溢出 |
"1e-50" | NULL | 0.000000f | 下溢 |
1.4 注意事项
- 错误检测:
- 方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败。
- 细节:
- 若 endptr == str:表示未解析出任何有效数字(如输入为 "HelloWorld")。
- 若 *endptr != '\0':表示部分成功转换如输入为 "123.45abc",endptr 指向 'a')。
- 若 *endptr == '\0':表示完全成功转换(如输入为 "123.45")。
- 溢出处理:
- 条件:当输入的数值超出 float 的表示范围时,strtof() 会设置 errno 为 ERANGE。
- 行为:
- 正溢出:返回 HUGE_VALF(inf)。
- 负溢出:返回 -HUGE_VALF(-inf)。
- 建议:在调用 strtof() 前,应清除 errno(如 errno = 0),以便后续检测。
- 科学计数法支持:strtof() 支持科学计数法(如 "1.23e4" 或 "1.23E-4"),这是 atof() 等函数不具备的特性。
- 推荐使用:相比 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,具体行为取决于实现)。
错误处理与范围检查相关概念:
- errno
- 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码。
- 作用:当 strtod() 等函数检测到错误(如数值溢出或下溢)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型。
- 使用建议:在调用 strtod() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误。
- ERANGE
- 含义:RANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)。
- 使用场景:当 strtod() 检测到输入的字符串表示的数值超出 double 的表示范围(过大或过小)时,会将 errno 设置为 ERANGE,表明发生了溢出或下溢错误。
- HUGE_VAL
- 含义:HUGE_VAL 是一个宏常量(定义在 <math.h> 头文件中),表示正无穷大(inf)的 double 值。
- 使用场景:当 strtod() 发生正溢出时,返回 HUGE_VAL(inf)。
- 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 转换规则
- 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等。
- 识别正负号:支持在数字前添加可选的符号字符:
- '+' 表示最终数值为正数。
- '-' 表示最终数值为负数。
- 若未指定符号,默认数值为正数。
- 读取数字:解析字符串中的数字部分,支持以下格式:
- 整数部分(如 "123")。
- 小数部分(如 ".123" 或 "123.456")。
- 指数部分(如 "1.23e4" 或 "1.23E-4")。
- 停止转换:遇到第一个不符合浮点数规则的字符时停止解析,后续字符将被忽略。
- 返回结果:将解析的数字转换为 double 类型返回。
- 错误处理:
- 完全成功转换:
- endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证。
- 示例:"3.1415926", NULL → 返回 3.141593。
- 部分成功转换:
- endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证。
- 示例:"3.14abc", NULL → 返回 3.14,endptr 指向 'a'。
- 无效输入:
- endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)。
- 示例:"HelloWorld", NULL → 返回 0.0f,endptr 指向 'H'。
- 溢出处理:需结合 errno 和 endptr 进行判断。
- 正溢出:
- 返回 HUGE_VAL(表示正无穷大,inf),并设置 errno 为 ERANGE。
- 示例:"1e500", NULL → 返回 HUGE_VAL。
- 负溢出:
- 返回 -HUGE_VAL(表示负无穷大,-inf),并设置 errno 为 ERANGE。
- 示例:"-1e500", NULL → 返回 -HUGE_VAL。
- 下溢:
- 返回 0.0,并可能设置 errno 为 ERANGE(具体行为取决于实现)。
- 示例:"1e-500", NULL → 返回 0.0。
- 正溢出:
- 完全成功转换:
转换示例:
输入字符串 | endptr 参数 | 返回值 | 说明 |
---|---|---|---|
"3.1415926" | NULL | 3.141593 | 完全成功转换 |
"-2.71828" | NULL | -2.718280 | 完全成功转换(负数) |
" +123.456" | NULL | 123.456000 | 忽略前导空格 |
"3.14abc" | NULL | 3.140000 | 部分成功转换,endptr 指向 'a' |
"HelloWorld" | NULL | 0.000000 | 无效输入,endptr 指向 'H' |
"1.23e4" | NULL | 12300.000000 | 科学计数法转换 |
"1e500" | NULL | HUGE_VAL(inf) | 正溢出 |
"-1e500" | NULL | -HUGE_VAL(-inf) | 负溢出 |
"1e-500" | NULL | 0.000000 | 下溢 |
2.4 注意事项
- 错误检测:
- 方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败。
- 细节:
- 若 endptr == str:表示未解析出任何有效数字(如输入为 "HelloWorld")。
- 若 *endptr != '\0':表示部分成功转换如输入为 "123.45abc",endptr 指向 'a')。
- 若 *endptr == '\0':表示完全成功转换(如输入为 "123.45")。
- 溢出处理:
- 条件:当输入的数值超出 double 的表示范围时,strtod() 会设置 errno 为 ERANGE。
- 行为:
- 正溢出:返回 HUGE_VAL(inf)。
- 负溢出:返回 -HUGE_VAL(-inf)。
- 建议:在调用 strtod() 前,应清除 errno(如 errno = 0),以便后续检测。
- 科学计数法支持:strtod() 支持科学计数法(如 "1.23e4" 或 "1.23E-4"),这是 atof() 等函数不具备的特性。
- 推荐使用:相比 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,具体行为取决于实现)。
错误处理与范围检查相关概念:
- errno
- 含义:errno 是一个全局变量(类型为 int,定义在 <errno.h> 头文件中),用于存储最近一次函数调用产生的错误代码。
- 作用:当 strtold() 等函数检测到错误(如数值溢出或下溢)时,会将 errno 设置为特定的错误码(如 ERANGE),以指示错误类型。
- 使用建议:在调用 strtold() 之前,应清除 errno(例如,通过 errno = 0),以便在转换后能够正确检测到是否发生了错误。
- ERANGE
- 含义:RANGE 是一个宏常量(通常值为 34,定义在 <errno.h> 头文件中),表示 “结果超出范围”(Range Error)。
- 使用场景:当 strtold() 检测到输入的字符串表示的数值超出 long double 的表示范围(过大或过小)时,会将 errno 设置为 ERANGE,表明发生了溢出或下溢错误。
- HUGE_VALL
- 含义:HUGE_VALL 是一个宏常量(定义在 <math.h> 头文件中),表示正无穷大(inf)的 long double 值。
- 使用场景:当 strtold() 发生正溢出时,返回 HUGE_VALL(inf)。
- 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 转换规则
- 忽略前导空格:在解析字符串时,自动跳过字符串开头处的所有空白字符,包括空格(' ')、制表符('\t')、换行符('\n')等。
- 识别正负号:支持在数字前添加可选的符号字符:
- '+' 表示最终数值为正数。
- '-' 表示最终数值为负数。
- 若未指定符号,默认数值为正数。
- 读取数字:解析字符串中的数字部分,支持以下格式:
- 整数部分(如 "123")。
- 小数部分(如 ".123" 或 "123.456")。
- 指数部分(如 "1.23e4" 或 "1.23E-4")。
- 停止转换:遇到第一个不符合浮点数规则的字符时停止解析,后续字符将被忽略。
- 返回结果:将解析的数字转换为 long double 类型返回。
- 错误处理:
- 完全成功转换:
- endptr 指向字符串末尾的空字符 '\0',可通过 if (*endptr == '\0') 验证。
- 示例:"3.1415926535", NULL → 返回 3.141593。
- 部分成功转换:
- endptr 指向第一个非数字字符,可通过 if (*endptr != '\0') 验证。
- 示例:"3.14abc", NULL → 返回 3.14,endptr 指向 'a'。
- 无效输入:
- endptr 指向原始字符串起始地址,可通过 if (endptr == str) 验证(str 为原始字符串指针)。
- 示例:"HelloWorld", NULL → 返回 0.0f,endptr 指向 'H'。
- 溢出处理:需结合 errno 和 endptr 进行判断。
- 正溢出:
- 返回 HUGE_VALL(表示正无穷大,inf),并设置 errno 为 ERANGE。
- 示例:"1e5000", NULL → 返回 HUGE_VALL。
- 负溢出:
- 返回 -HUGE_VALL(表示负无穷大,-inf),并设置 errno 为 ERANGE。
- 示例:"-1e5000", NULL → 返回 -HUGE_VALL。
- 下溢:
- 返回 0.0f,并可能设置 errno 为 ERANGE(具体行为取决于实现)。
- 示例:"1e-5000", NULL → 返回 0.0L。
- 正溢出:
- 完全成功转换:
转换示例:
输入字符串 | endptr 参数 | 返回值 | 说明 |
---|---|---|---|
"3.1415926535" | NULL | 3.141593L | 完全成功转换 |
"-2.718281828" | NULL | -2.718282L | 完全成功转换(负数) |
" +123.456" | NULL | 123.456000L | 忽略前导空格 |
"3.14abc" | NULL | 3.140000L | 部分成功转换,endptr 指向 'a' |
"HelloWorld" | NULL | 0.000000L | 无效输入,endptr 指向 'H' |
"1.23e4" | NULL | 12300.000000L | 科学计数法转换 |
"1e5000" | NULL | HUGE_VALL(inf) | 正溢出 |
"-1e5000" | NULL | -HUGE_VALL(-inf) | 负溢出 |
"1e-5000" | NULL | 0.000000L | 下溢 |
3.4 注意事项
- 错误检测:
- 方法:通过检查 endptr 是否等于原始字符串的起始地址(str)来判断转换是否完全失败。
- 细节:
- 若 endptr == str:表示未解析出任何有效数字(如输入为 "HelloWorld")。
- 若 *endptr != '\0':表示部分成功转换如输入为 "123.45abc",endptr 指向 'a')。
- 若 *endptr == '\0':表示完全成功转换(如输入为 "123.45")。
- 溢出处理:
- 条件:当输入的数值超出 long double 的表示范围时,strtold() 会设置 errno 为 ERANGE。
- 行为:
- 正溢出:返回 HUGE_VALL(inf)。
- 负溢出:返回 -HUGE_VALL(-inf)。
- 建议:在调用 strtold() 前,应清除 errno(如 errno = 0),以便后续检测。
- 科学计数法支持:strtold() 支持科学计数法(如 "1.23e4" 或 "1.23E-4"),这是 atof() 等函数不具备的特性。
- 推荐使用:相比 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) | float | FLT_MIN 到 FLT_MAX(通常为 1.175494e-38 到 3.402823e+38) | 需要处理单精度浮点数的转换 | 无效输入时返回 0.0f; 正溢出时返回 +HUGE_VALF(inf); 负溢出时返回 -HUGE_VALF(-inf); 下溢时可能返回 0.0f 或次正规数(取决于实现),并设置 errno 为 ERANGE(仅溢出时设置) |
strtod | 将字符串转换为双精度浮点型(double) | double | DBL_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 double | LDBL_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)可能因平台和编译器实现而异,因此在跨平台开发时需要注意这些差异。
相关文章:

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…...
解决 idea提示`SQL dialect is not configured` 问题
前言 在 Java 开发中,尤其是使用 IntelliJ IDEA 或 MyBatis 等框架时,开发者常会遇到 SQL dialect is not configured 的警告或错误。这一问题不仅影响代码的高亮和智能提示功能,还可能导致表结构解析失败、语法校验失效等问题。 一、问题分…...
springboot的test模块使用Autowired注入失败
springboot的test模块使用Autowired注入失败的原因: 注入失败的原因可能是用了junit4的包的Test注解 import org.junit.Test;解决方法:再加上RunWith(SpringRunner.class)注解即可 或者把Test由junit4改成junit5的注解,就不用加上RunWith&…...

日志收集工具-Filebeat
提示:windows 环境下 Filebeat 的安装与使用 文章目录 前言一、安装二、配置部署三、启动测试 前言 Filebeat 一般用于日志采集,由两部分组成 :Harvesters 和 prospector Harvesters采集器:逐行读取单个文件的内容,并…...
【PCIe总线】 -- PCI、PCIe相关实现
PCI、PCIe相关概念和知识点 【PCIe总线】-- PCI、PCIe基础知识点整理 【PCIe】非常适合初学的pcie博客(PCIe知识整理) PCIe具体实现 【PCIe】如何获取PCIe的BAR空间大小?...

Vue3学习(4)- computed的使用
1. 简述与使用 作用:computed 用于基于响应式数据派生出新值,其值会自动缓存并在依赖变化时更新。 缓存机制:依赖未变化时直接返回缓存值,避免重复计算(通过 _dirty 标志位实现)。响应式更新&…...

手机上网可以固定ip地址吗?详细解析
在移动互联网时代,手机已成为人们日常上网的主要设备之一。无论是工作、学习还是娱乐,稳定的网络连接都至关重要。许多用户对IP地址的概念有所了解,尤其是固定IP地址的需求。那么,手机上网能否固定IP地址?又该如何实现…...
电脑同时连接内网和外网的方法,附外网连接局域网的操作设置
对于工作一般都设置在内网网段中,而同时由于需求需要连接外网,一般只能通过内网和外网的不断切换进行设置,如果可以同时连接内网和外网会更加便利,同时连接内网和外网方法具体如下。 一、电脑怎么弄可以同时连接内网和外网&#…...

如何在Unity中实现点击一个按钮跳转到哔哩哔哩
1.创建一个按钮 2.编写一个脚本(你可以把链接改成你想要跳转的网站) using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;public class JumpToBilibili : MonoBehaviour {void Start(){gameObject.…...
DHCP 动态主机配置协议(Dynamic host configuration protocol)逐层封装过程: DHCP --> UDP --> IP
📦 DHCP 报文逐层封装结构(自上而下) 应用层(DHCP 报文) ↓ 传输层(UDP 首部) ↓ 网络层(IP 首部) ↓ 数据链路层(以太网帧头) ↓ 物理层&#x…...

PySide6 GUI 学习笔记——常用类及控件使用方法(单行文本控件QLineEdit)
文章目录 QLineEdit 介绍常用方法QLineEdit.EchoMode 取值光标相关方法文本选择方法输入格式化字符(Input Mask)常用信号QLineEdit 实例 QLineEdit 介绍 QLineEdit 是 PySide6(Qt for Python)中用于单行文本输入的控件。它支持文本…...

【数据结构】6. 时间与空间复杂度
文章目录 一、算法效率1、算法的复杂度 二、时间复杂度1、时间复杂度的概念2、大O的渐进表示法3、常见时间复杂度计算1)实例12)实例23)实例34)实例45)实例56)实例67)实例78)实例8 三…...
Python 函数全攻略:函数进阶(生成器、闭包、内置函数、装饰器、推导式)
一、默认参数中的易错点 问题: 当函数的默认参数是可变类型(如 list, dict)时,存在“坑”。 现象: def func(a2=[]): # a2 默认是一个空列表a2.append(2)print(a2)func() # 第一次调用,a2 默认为 [],输出 [2] func([]) # 传入新列表,输出 [2] func([1]) # 传入带元素的…...

基于springboot的藏文古籍系统
博主介绍:高级开发,从事互联网行业六年,熟悉各种主流语言,精通java、python、php、爬虫、web开发,已经做了多年的设计程序开发,开发过上千套设计程序,没有什么华丽的语言,只有实实在…...

重构城市应急指挥布控策略 ——无人机智能视频监控的破局之道
在突发事件、高空巡查、边远区域布控中,传统摄像头常常“看不到、跟不上、调不动”。无人机智能视频监控系统,打破地面视角局限,以“高空布控 AI分析 实时响应”赋能政企单位智能化管理。在城市应急指挥中心的大屏上,一场暴雨正…...

声音信号的基频检测(python版本)
import math import wave import array import functools from abc import ABC, abstractmethod import matplotlib import matplotlib.pyplot as plt from matplotlib.gridspec import GridSpec import os import sys# 设计模式部分 class PreprocessStrategy(ABC):"&q…...

STM32 控制12VRGB灯带颜色亮度调节,TFTLCD显示
接了一个同学的小项目,要实现控制一个实体,控制灯带的亮度为红/绿/蓝/白/黄以及亮度的叠加。 时间要的比较急,要两天实现,因此不能打板,只能采用现有模块拼接。 一. 实施方案 一开始觉得很简单,就是使用五…...
Hive开窗函数的进阶SQL案例
一、开窗函数基础 1. 定义与作用 开窗函数(Window Functions)在保留原始行数据的同时,对分组内的行进行聚合或排序分析,常用于累计计算、排名、移动平均等场景。与普通聚合函数(如SUM、AVG)的区别…...

【JJ斗地主-注册安全分析报告】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞 …...

《绩效管理》要点总结与分享
目录 绩效管理与目标设定 绩效管理的循环:PDCA 绩效目标的设定要点 绩效设定的工具:SMART法则 绩效跟踪与评估 刻板印象:STAR法 晕轮效应:对比评价法 近因效应:关键事项评估表 绩效面谈 面谈前准备工作 汉堡…...

Microsoft前后端不分离编程新风向:cshtml
文章目录 什么是CSHTML?基础语法内联表达式代码块控制结构 布局页面_ViewStart.cshtml_Layout.cshtml使用布局 模型绑定强类型视图模型集合 HTML辅助方法基本表单验证 局部视图创建局部视图使用局部视图 高级特性视图组件依赖注入Tag Helpers 性能优化缓存捆绑和压缩…...

【评测】用Flux的图片文本修改的PS效果
【评测】Flux的图片文本修改的PS效果 1. 百度图库找一张有英文的图片 2. 打开https://playground.bfl.ai/image/edit上传图片 3. 输入提示词 “change brarfant to goodbeer” 图片的文字被修改了...
青少年编程与数学 01-011 系统软件简介 01 MS-DOS操作系统
青少年编程与数学 01-011 系统软件简介 01 MS-DOS操作系统 1. MS-DOS的历史背景1.1 诞生背景1.2 发展历程1.3 与Windows的关系 2. MS-DOS的技术细节2.1 系统架构2.2 启动过程2.3 内存管理2.4 设备驱动程序 3. MS-DOS的用户界面3.1 命令行界面3.2 配置文件 4. MS-DOS的应用程序与…...

数据库管理-第334期 Oracle Database 23ai测试版RAC部署文档(20250607)
数据库管理334期 2024-06-07 数据库管理-第334期 Oracle Database 23ai测试版RAC部署文档(20240607)1 环境与安装介质2 操作标准系统配置2.1 关闭防火墙2.2 关闭SELinux2.3 关闭avahi-daemon2.4 时间同步配置 3 存储服务器配置3.1 配置本地yum源3.2 安装…...
springCloud2025+springBoot3.5.0+Nacos集成redis从nacos拉配置起服务
文章目录 前言一、网关gateway选型1. 响应式编程模型2. 网关的特定需求3. 技术栈一致性4. 性能对比5. 实际应用场景优势 二、redis的集成1.引入库2.配置类A、自定义配置类RedisAfterNacosAutoConfigurationB、自定义配置类RedisConfig 总结 前言 最近在搭建最新的springCloud …...

AI生成的基于html+marked.js实现的Markdown转html工具,离线使用,可实时预览 [
有一个markdown格式的文档,手头只有notepad的MarkdownPanel插件可以预览,但是只能预览,不能直接转换为html文件下载,直接复制预览的内效果又不太好,度娘也能找到很多工具,但是都需要在线使用。所以考虑用AI…...

机器学习:load_predict_project
本文目录: 一、project目录二、utils里的两个工具包(一)common.py(二)log.py 三、src文件夹代码(一)模型训练(train.py)(二)模型预测(…...
OkHttp 3.0源码解析:从设计理念到核心实现
本文通过深入分析OkHttp 3.0源码,揭示其高效HTTP客户端的实现奥秘,包含核心设计理念、关键组件解析、完整工作流程及实用技巧。 一、引言:为什么选择OkHttp? 在Android和Java生态中,OkHttp已成为HTTP客户端的标准选择…...

【storage】
文章目录 1、RAM and ROM2、DRAM and SRAM2、Flash Memory(闪存)4、DDR and SPI NOR Flash5、eMMC6、SPI NOR vs SPI NAND vs eMMC vs SD附录——prototype and demo board附录——U盘、SD卡、TF卡、SSD参考 1、RAM and ROM RAM(Random Acce…...
微信小程序带参分享、链接功能
分享链接的功能是右上角点...然后复制链接,可以直接点击 #小程序://**商城/p5XqHti******* 这种链接直接从其他地方跳转到小程序 wx.onCopyUrl(() > {return {query: "shareCode" this.shareCode,}; }); query就是参数,直接在onload里…...