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
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/84072.shtml
英文地址,請注明出處:http://en.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;屬性…