安全地將字串轉換為數字 strtoX 函式

Version >= C99

從 C99 開始,C 庫有一組安全轉換函式,將字串解釋為數字。它們的名稱形式為 strtoX,其中 Xluld 等之一,用於確定轉換的目標型別

double strtod(char const* p, char** endptr);
long double strtold(char const* p, char** endptr);

它們會檢查轉換是否存在溢位或下溢:

double ret = strtod(argv[1], 0); /* attempt conversion */

/* check the conversion result. */
if ((ret == HUGE_VAL || ret == -HUGE_VAL) && errno == ERANGE) 
    return;  /* numeric overflow in in string */
else if (ret == HUGE_VAL && errno == ERANGE) 
    return; /* numeric underflow in in string */

/* At this point we know that everything went fine so ret may be used */

如果字串實際上根本不包含任何數字,則 strtod 的這種用法將返回 0.0

如果這不令人滿意,可以使用附加引數 endptr。它是指向指標的指標,指標指向字串中檢測到的數字的末尾。如果設定為 0,如上所述,或者 NULL,則會被忽略。

endptr 引數提供指示是否已成功轉換,如果成功,則表示數字結束的位置:

char *check = 0;
double ret = strtod(argv[1], &check); /* attempt conversion */

/* check the conversion result. */
if (argv[1] == check) 
    return; /* No number was detected in string */
else if ((ret == HUGE_VAL || ret == -HUGE_VAL) && errno == ERANGE) 
    return; /* numeric overflow in in string */
else if (ret == HUGE_VAL && errno == ERANGE) 
    return; /* numeric underflow in in string */

/* At this point we know that everything went fine so ret may be used */

有類似的函式可以轉換為更寬的整數型別:

long strtol(char const* p, char** endptr, int nbase);
long long strtoll(char const* p, char** endptr, int nbase);
unsigned long strtoul(char const* p, char** endptr, int nbase);
unsigned long long strtoull(char const* p, char** endptr, int nbase);

這些函式有第三個引數 nbase,它儲存寫入數字的數字基數。

long a = strtol("101",   0, 2 ); /* a = 5L */
long b = strtol("101",   0, 8 ); /* b = 65L */
long c = strtol("101",   0, 10); /* c = 101L */
long d = strtol("101",   0, 16); /* d = 257L */
long e = strtol("101",   0, 0 ); /* e = 101L */
long f = strtol("0101",  0, 0 ); /* f = 65L */
long g = strtol("0x101", 0, 0 ); /* g = 257L */

nbase 的特殊值 0 表示字串的解釋方式與在 C 程式中解釋數字文字的方式相同:0x 的字首對應十六進位制表示,否則前導 0 是八進位制,所有其他數字看作十進位制。

因此,將命令列引數解釋為數字的最實用方法是

int main(int argc, char* argv[] {
    if (argc < 1)
        return EXIT_FAILURE; /* No number given. */

    /* use strtoull because size_t may be wide */
    size_t mySize = strtoull(argv[1], 0, 0);

    /* then check conversion results. */

     ...

    return EXIT_SUCCESS;
}

這意味著可以使用八進位制,十進位制或十六進位制引數呼叫程式。