LoginSignup
1
0

[C言語] atoiをゼロから書く

Last updated at Posted at 2024-01-23

ゼロからシリーズ

この記事はゼロからcのライブラリを再実装するシリーズです。

atoi の動作概要

atoi は char * 型の値を int 型の値へ変換するものです。

詳しい動作

  • appleの atoi を参照すると strtollong の値を int をキャストしているようです。
  • appleの strtol を参照すると詳しいことが見えてきそうです。
    • はじめのcharポインタから isspace(3) に準拠したスペースはすべて無視する仕様のようです。
      • isspace(3) -> , \t, \n, \v, \f, \r
    • はじめの空白を除いたcharポインタは -+ を1バイトだけ許容する仕様のようです。
    • 上記のcharポインタの次に複数の数字を0~9を許容するようで、数字でないものがcharポインタに入っているとそこで処理を抜ける仕様のようです。
    • char * 型の値を long 型の値へ変換する際にlongをオーバーフローしたら LONG_MAXLONG_MIN をreturnするようです。

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));
}
1
0
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0