ゼロからシリーズ
この記事はゼロからcのライブラリを再実装するシリーズです。
atoi の動作概要
atoi は char * 型の値を int 型の値へ変換するものです。
詳しい動作
-
appleの
atoiを参照するとstrtolのlongの値をintをキャストしているようです。 -
appleの
strtolを参照すると詳しいことが見えてきそうです。- はじめのcharポインタから
isspace(3)に準拠したスペースはすべて無視する仕様のようです。-
isspace(3)->,\t,\n,\v,\f,\r
-
- はじめの空白を除いたcharポインタは
-か+を1バイトだけ許容する仕様のようです。 - 上記のcharポインタの次に複数の数字を
0~9を許容するようで、数字でないものがcharポインタに入っているとそこで処理を抜ける仕様のようです。 -
char *型の値をlong型の値へ変換する際にlongをオーバーフローしたらLONG_MAXかLONG_MINをreturnするようです。
- はじめのcharポインタから
atoi 実装
isspace 実装
int ft_isspace(char c)
{
if (c == ' ' || c == '\t' || c == '\n'
|| c == '\v' || c == '\f' || c == '\r')
return (1);
return (0);
}
long のオーバーフロー検知を実装
int overflowl(int sign, long l, char next)
{
if (sign == 1)
if (LONG_MAX / 10 < l
|| (LONG_MAX / 10 == l && LONG_MAX % 10 <= next - '0'))
return (1);
if (sign == -1)
if (LONG_MIN / -10 < l
|| (LONG_MIN / -10 == l && LONG_MIN % -10 * -1 <= next - '0'))
return (-1);
return (0);
}
atoi を実装
#include <limits.h>
int ft_atoi(const char *str)
{
long ret;
int sign;
ret = 0;
sign = 1;
while (ft_isspace(*str))
str++;
if (*str == '-' || *str == '+')
if (*str++ == '-')
sign = -1;
while (*str)
{
if ('0' <= *str && *str <= '9')
{
if (overflowl(sign, ret, *str) == 1)
return ((int)LONG_MAX);
if (overflowl(sign, ret, *str) == -1)
return ((int)LONG_MIN);
ret = ret * 10 + (long)(*str - '0');
str++;
}
else
break ;
}
return ((int)(ret * sign));
}
まとめ
今回はatoiをゼロから再実装しました。
All in one code
#include <limits.h>
int ft_isspace(char c)
{
if (c == ' ' || c == '\t' || c == '\n'
|| c == '\v' || c == '\f' || c == '\r')
return (1);
return (0);
}
int overflowl(int sign, long l, char next)
{
if (sign == 1)
if (LONG_MAX / 10 < l
|| (LONG_MAX / 10 == l && LONG_MAX % 10 <= next - '0'))
return (1);
if (sign == -1)
if (LONG_MIN / -10 < l
|| (LONG_MIN / -10 == l && LONG_MIN % -10 * -1 <= next - '0'))
return (-1);
return (0);
}
int ft_atoi(const char *str)
{
long ret;
int sign;
ret = 0;
sign = 1;
while (ft_isspace(*str))
str++;
if (*str == '-' || *str == '+')
if (*str++ == '-')
sign = -1;
while (*str)
{
if ('0' <= *str && *str <= '9')
{
if (overflowl(sign, ret, *str) == 1)
return ((int)LONG_MAX);
if (overflowl(sign, ret, *str) == -1)
return ((int)LONG_MIN);
ret = ret * 10 + (long)(*str - '0');
str++;
}
else
break ;
}
return ((int)(ret * sign));
}