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)可能因平臺和編譯器實現而異,因此在跨平臺開發時需要注意這些差異。