C atof 구현
저는 C의 초보자입니다. 현재 레이트 레이서를 구축하기 위해 atof를 구현하고 있지만 프로그램을 효율적으로 작성하는 방법을 배우고 있습니다.
양도
명령
프로그램은 장면 설명 파일을 인수로 사용하여 개체를 생성합니다. 이러한 매개 변수 중 일부는 부동입니다. 파일의 예.

파일을 파싱하고 있습니다. 함수 당 허용되는 줄이 제한되어 있고 현재 이중 포인터가 작동하는 방식을 배우고 있으므로 이중 문자 포인터를 사용하고 있습니다. 이러한 일 함수의 예를 사용 lc_atof
.
int a_parsing(char *str, t_pars *data)
{
if (*(str++) == 'A')
{
if (((data->a_ratio = lc_atof(&str)) >= 0.0) && data->a_ratio <= 1.0 && errno == 0)
//
if (((data->a_R = lc_atoi(&str)) >= 0) && data->a_R <= 255 && errno == 0)
if (*(str++) = ',' && ((data->a_G = lc_atoi(&str)) >= 0) && data->a_G <= 255 && errno == 0)
if (*(str++) = ',' && ((data->a_B = lc_atoi(&str)) >= 0) && data->a_B <= 255 && errno == 0)
return (skip_space(&str));
}
return (0);
}
검토 할 현재 코드 :
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <float.h>
static float conversion(char **str)
{
double d_nbr;
double power;
d_nbr = 0.0;
power = 10.0;
while (isdigit(**str))
{
d_nbr = d_nbr * 10.0 + (**str - 48);
if (d_nbr > FLT_MAX)
{
errno = EIO;
return (-1);
}
(*str)++;
}
if (**str == '.')
{
(*str)++;
if (isdigit(**str))
{
d_nbr = d_nbr * 10.0 + (**str - 48);
if (d_nbr > FLT_MAX)
{
errno = EIO;
return (-1);
}
(*str)++;
return ((float)(d_nbr / power));
}
}
errno = EIO;
return (-1);
}
float lc_atof(char **str)
{
float n;
int sign;
n = 0.0;
sign = 1.0;
if (!str || !*str)
{
errno = EIO;
return (-1);
}
while (isspace(**str))
(*str)++;
if (**str == '+' || **str == '-')
{
if (**str == '-')
sign = -1.0;
(*str)++;
}
if (!isdigit(**str))
{
errno = EIO;
return (-1);
}
if ((n = conversion(str)) == 0 && errno != 0)
return (-1);
return (sign * n);
}
내가 만든 실제 atof에 대한 유일한 조정은 이중 문자 포인터를 인수로 사용하고 오류가 발생하면 -1을 반환하는 것입니다.
모든 입력은 대단히 감사합니다.
답변
휴대 성
이 코드가 ASCII를 사용한다는 보장은 없으므로 마법의 숫자 '0'
보다 사용하는 것이 더 낫습니다 48
. 사용 '0'
하면 더 읽기 쉽고 이해하기 쉽습니다.
lc_atof
문자열 종료 또는 줄 끝을 올바르게 처리하지 않음
이 코드는 NULL로 끝나는 문자열이나 줄 끝 문자를 처리하지 않습니다. 이 함수 isspace()
는 true
줄 끝을 반환 하므로 코드가 바로 지나갈 것입니다.
while (isspace(**str))
(*str)++;
if (**str == '+' || **str == '-')
{
if (**str == '-')
sign = -1.0;
(*str)++;
}
if (!isdigit(**str))
{
errno = EIO;
return (-1);
}
복잡성
나는 당신이 이것을 검토하도록 요청하지 않았지만 if
예제 호출 함수 의 각 명령문 의 복잡성 이 너무 커서 이전 검토에서 오류를 만들었습니다.
int a_parsing(char* str, t_pars* data)
{
if (*(str++) == 'A')
{
if (((data->a_ratio = lc_atof(&str)) >= 0.0) && data->a_ratio <= 1.0 && errno == 0)
//
if (((data->a_R = lc_atoi(&str)) >= 0) && data->a_R <= 255 && errno == 0)
if (*(str++) = ',' && ((data->a_G = lc_atoi(&str)) >= 0) && data->a_G <= 255 && errno == 0)
if (*(str++) = ',' && ((data->a_B = lc_atoi(&str)) >= 0) && data->a_B <= 255 && errno == 0)
return (skip_space(&str));
}
return (0);
}
코드를 다음과 같이 다시 작성합니다.
#define MAX_COLOR 0xFF
int a_parsing_prime(char* str, t_pars* data)
{
if (*(str++) == 'A')
{
data->a_ratio = lc_atof(&str);
if (!errno && data->a_R <= MAX_COLOR)
{
if (*(str++) = ',')
{
data->a_G = lc_atoi(&str);
if (!errno && data->a_G <= MAX_COLOR)
{
if (*(str++) = ',')
{
data->a_B = lc_atoi(&str);
if (!errno && data->a_B <= MAX_COLOR)
{
return (skip_space(&str));
}
}
}
}
}
}
return (0);
}
기능의 복잡성을 실제로 보여줍니다.
EIO
오류보고를 선택 하는 것은 매우 모호합니다.lc_atof
입력이나 출력을하지 않습니다. 왜 IO 오류를보고해야합니까? 반환 유형이 결과를 나타낼 수없는 경우 (예d_nbr > FLT_MAX
:) 논리적 선택은ERANGE
또는EOVERFLOW
입니다. 잘못된 인수 (예 :)로 인해 변환을 완료 할 수없는 경우!isdigit(**str)
논리적 선택은EINVAL
.즉
errno
, 라이브러리 기능의 설정 을 보증하지 않습니다 . 오랜 전통은errno
시스템 호출에만 설정 하는 것입니다. 이 전통이 요즘 점점 더 위반되고 있다는 것을 알고 있지만 여전히 그렇습니다. 다른 오류보고 수단이있는 경우이를 고수하십시오.inout 매개 변수 (
str
귀하의 경우)를 사용하는 것은 권장되지 않습니다. 호출자 측과 수신자 측 모두에서 코드를 불필요하게 복잡하게 만듭니다. 피 호출자는 추가 간접 지정을 너무 많이 사용하고 괄호 안에 괄호를 넣는 것에 대해 걱정해야(**str)++
합니다. 차례로 호출자는 구문 분석이 시작된 위치를 추적하지 못합니다 (예 : 잘못된 번호를 기록해야 함). 어떻게strtof
처리 하는지보세요 :float strtof(const char *restrict nptr, char **restrict endptr);
여기는
nptr
in-only,endptr
out-only입니다.소수점 이하 한 자리 만 처리하여 함수의 유용성을 제한하기로 결정한 것에 놀랐습니다. 그것들을 모두 처리하는 것은 큰 노력이 아니며 이점이 훨씬 큽니다.
반환 값을 괄호로 묶을 필요가 없습니다.
return
함수가 아니라 연산자입니다.