安全地将字符串转换为数字 strtoX 函数
Version >= C99
从 C99 开始,C 库有一组安全转换函数,将字符串解释为数字。它们的名称形式为 strtoX
,其中 X
是 l
,ul
,d
等之一,用于确定转换的目标类型
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;
}
这意味着可以使用八进制,十进制或十六进制参数调用程序。