直到今天,在我需要这样的东西的少数情况下,我只使用了简单的程序,而我并不关心安全性,所以我使用了简单的atoi()。
然而,今天我需要做一些更严肃的程序,我研究了从字符串到数字的许多不同的形式:atoi vs atol vs strtol vs strtoul vs sscanf。
我对这些都不满意。strtol() (及其家族)是最安全的标准之一,也是一个非常快速的标准,但它的使用非常困难,所以我决定为它编写一个安全而简单的接口。strtoi() (libbsd)比strtol()更容易使用,但仍然有点复杂。我决定使用固定宽度的整数,就像我在所有代码中所做的那样。我还为strtof()和公司做了一个界面。
必要条件:
strtol()而不是strtoi()编写,但它更复杂,并且errno有strtoi()没有的问题)。有符号整数:
strtoi_s.h:
#pragma once /* libalx/base/stdlib/strto/strtoi_s.h */
#include <errno.h>
#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
__attribute__((nonnull, warn_unused_result))
inline
int strtoi8_s (int8_t *restrict num, const char *restrict str,
int base);
__attribute__((nonnull, warn_unused_result))
inline
int strtoi16_s (int16_t *restrict num, const char *restrict str,
int base);
__attribute__((nonnull, warn_unused_result))
inline
int strtoi32_s (int32_t *restrict num, const char *restrict str,
int base);
__attribute__((nonnull, warn_unused_result))
inline
int strtoi64_s (int64_t *restrict num, const char *restrict str,
int base);
inline
int strtoi8_s (int8_t *restrict num, const char *restrict str,
int base)
{
int rstatus;
*num = strtoi(str, NULL, base, INT8_MIN, INT8_MAX, &rstatus);
switch (rstatus) {
case 0:
return 0;
case ENOTSUP:
return rstatus;
case ECANCELED:
case EINVAL:
case ERANGE:
default:
return -rstatus;
}
}
inline
int strtoi16_s (int16_t *restrict num, const char *restrict str,
int base)
{
int rstatus;
*num = strtoi(str, NULL, base, INT16_MIN, INT16_MAX, &rstatus);
switch (rstatus) {
case 0:
return 0;
case ENOTSUP:
return rstatus;
case ECANCELED:
case EINVAL:
case ERANGE:
default:
return -rstatus;
}
}
inline
int strtoi32_s (int32_t *restrict num, const char *restrict str,
int base)
{
int rstatus;
*num = strtoi(str, NULL, base, INT32_MIN, INT32_MAX, &rstatus);
switch (rstatus) {
case 0:
return 0;
case ENOTSUP:
return rstatus;
case ECANCELED:
case EINVAL:
case ERANGE:
default:
return -rstatus;
}
}
inline
int strtoi64_s (int64_t *restrict num, const char *restrict str,
int base)
{
int rstatus;
*num = strtoi(str, NULL, base, INT64_MIN, INT64_MAX, &rstatus);
switch (rstatus) {
case 0:
return 0;
case ENOTSUP:
return rstatus;
case ECANCELED:
case EINVAL:
case ERANGE:
default:
return -rstatus;
}
}无符号整数:
它与前一个基本相同,所以我只发布一个函数
strtou_s.h:
inline
int strtou8_s (uint8_t *restrict num, const char *restrict str,
int base)
{
int rstatus;
*num = strtou(str, NULL, base, 0, UINT8_MAX, &rstatus);
switch (rstatus) {
case 0:
return 0;
case ENOTSUP:
return rstatus;
case ECANCELED:
case EINVAL:
case ERANGE:
default:
return -rstatus;
}
}浮点:
strtof_s.h:
#pragma once /* libalx/base/stdlib/strto/strtof_s.h */
#include <errno.h>
#include <stdlib.h>
/*
* `errno` needs to be cleared before calling these functions. If not, false
* negatives could happen (the function succeds, but it reports error).
*/
__attribute__((nonnull, warn_unused_result))
inline
int strtod_s (double *restrict num, const char *restrict str);
__attribute__((nonnull, warn_unused_result))
inline
int strtof_s (float *restrict num, const char *restrict str);
__attribute__((nonnull, warn_unused_result))
inline
int strtold_s (long double *restrict num, const char *restrict str);
inline
int strtod_s (double *restrict num, const char *restrict str)
{
char *endptr;
*num = strtod(str, &endptr);
if (*endptr != '\0')
return ENOTSUP;
if (errno == ERANGE)
return ERANGE;
if (str == endptr)
return -ECANCELED;
return 0;
}
inline
int strtof_s (float *restrict num, const char *restrict str)
{
char *endptr;
*num = strtof(str, &endptr);
if (*endptr != '\0')
return ENOTSUP;
if (errno == ERANGE)
return ERANGE;
if (str == endptr)
return -ECANCELED;
return 0;
}
inline
int strtold_s (long double *restrict num, const char *restrict str)
{
char *endptr;
*num = strtold(str, &endptr);
if (*endptr != '\0')
return ENOTSUP;
if (errno == ERANGE)
return ERANGE;
if (str == endptr)
return -ECANCELED;
return 0;
}函数有两个指针:第一个指向必须存储数字的变量;第二个指向要读取的字符串。整数函数还需要基函数,它遵循与strtol()中相同的规则。
返回值只是一个错误代码:
0和往常一样好,
> 0是指带有某些错误的有效转换(浮点中的部分转换,0或inf,.)。
< 0意味着无效的转换,或者根本没有转换。
示例:
char buf[BUFSIZ];
int64_t num;
if (!fgets(buf, ARRAY_SIZE(buf), stdin))
goto err;
if (strtoi64_s(&num, buf, 0))
goto err;
/* num is safe to be used now*/你认为界面可以用任何方式改进吗?
发布于 2019-08-28 18:15:29
strtol和家庭的主要优点是他们计算(免费!)转换结束的点。这是一个非常有价值的信息,因为通常在提取出要继续解析的数字之后。你的包装纸扔掉了。result)是相同的。把它分解成一个函数。https://codereview.stackexchange.com/questions/226969
复制相似问题