티스토리 뷰
이 줄 :
if (x == -2147483648)
당신이 생각하는대로하지 않습니다. C에는 음의 정수 상수가 없습니다. 이것은 단항 빼기 연산자를 적용하는 값이 2 ^ 31 인 부호없는 정수입니다. 즉,
x == -21...
컴파일러가 사용하는 C 표준에 따라 표현식 이 달라집니다.C99 또는 C11을 사용하면 괜찮습니다. 충분히 큰 부호있는 유형이 있습니다. long long은이 숫자에 대해 충분히 큰 것이 보장되므로 x와 -21 ... 둘 다 long long으로 변환 된 다음 비교됩니다. 그러나 C89 컴파일러를 사용하고 있고 컴퓨터에 충분한 형식이없는 경우 여기에서 구현 정의 동작을 수행합니다.
정수가 더 작은 크기의 부호있는 정수로 강등되거나 부호없는 정수가 해당 부호있는 정수로 변환 될 때 값을 표시 할 수없는 경우 결과는 구현에서 정의됩니다.
이것이 사람들이 한계를 사용하라고 말하는 이유입니다. 그들이 현학적이기 때문이 아니라 이것은 위험한 영역이기 때문입니다. limits.h에 포함 된 내용을 자세히 살펴보면 다음과 같은 줄을 찾을 수 있습니다.
#define INT_MIN (- INT_MAX - 1)
이 표현식에는 실제로 올바른 유형과 값이 있습니다.그 외에는 게시 한 코드에서 오류를 볼 수 없습니다. 이것이 문제가 아니
ft_intlen
거나
ft_strdup
잘못된 경우. 또는 테스트에서 함수를 잘못 호출하고 있습니다 (테스트를 호출 할 때 -21 ...에도 동일한 문제가 적용됨).-------------------
상태 : 유효하지 않은 해결이유 : WORKS_FOR_ME어쨌든 몇 가지 점이 향상되었습니다.
sizeof(char)
항상 1이며 필요하지 않습니다.- 캐스트하지 마십시오
malloc
- 특별한 경우 0을 처리하면 한 번에 처리하십시오.
-2147483648
매우 나쁩니다. 그게INT_MIN
목적입니다.- return은 함수가 아니므로 return하지 말고
(value)
returnvalue
합니다. - 안
s[len - 1]
좋은 감소, 모든 시간을len
루프를 입력하기 전에. 또는 호출len + 1
에서만 필요 하므로 반환하고 다음을 사용하여 호출하십시오.malloc
len
intlen
malloc
len + 1
ft_itoa.c
#include <stdbool.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <btstr.h>
int ft_intlen(int n) {
char buffer[8192];
return snprintf(buffer, sizeof buffer, "%i", n);
}
char * ft_itoa(int n) {
char * s;
size_t l, len;
bool fix_int_min = false;
if (!n) {
return mstrcpy("0");
}
if (-INT_MAX != INT_MIN && n == INT_MIN) {
++n;
fix_int_min = true;
}
len = ft_intlen(n);
if (!(s = malloc(len + 1))) {
return NULL;
}
if (n < 0) {
s[0] = '-';
n = -n;
}
s[l = len] = '\0';
while (n) {
s[--len] = (n % 10) + '0';
n /= 10;
}
if (fix_int_min) {
--l;
while (s[l] == '9') {
s[l++] = 0;
}
if (s[l] == '-') {
// realloc +1 and write "-1[0....0]\0"
} else {
++s[l];
}
}
return s;
}
main.c
#include <limits.h>
#include <stdio.h>
char * ft_itoa(int n);
void check(int n) {
printf("%i = %s\n", n, ft_itoa(n));
}
int main() {
check(0);
check(-1);
check(1);
check(23);
check(42);
check(4711);
check(1000);
check(INT_MAX);
check(1+INT_MIN);
check(INT_MIN);
}
결과
$ gcc -W -Wall -Wextra -lBtLinuxLibrary ft_itoa.c main.c -o ft_itoa && ./ft_itoa
0 = 0
-1 = -1
1 = 1
23 = 23
42 = 42
4711 = 4711
1000 = 1000
2147483647 = 2147483647
-2147483647 = -2147483647
-2147483648 = -2147483648
-------------------
그 수표는 필요하지 않습니다. 대신
unsigned
절대 값에 맞는 로 변환하십시오 .
size_t ft_uintlen(unsigned n)
{
size_t len = 0;
do {
++len;
n /= 10;
} while(n);
return len;
}
char *ft_itoa(int x)
{
char *s;
size_t len;
unsigned n;
int negative;
negative = x < 0;
n = negative ? 0-(unsigned)x : (unsigned)x;
len = ft_uintlen(n) + negative + 1;
if (!(s = (char*)malloc(len)))
return (NULL);
s[--len] = '\0';
if (negative)
s[0] = '-';
do {
s[--len] = (n % 10) + '0';
n /= 10;
} while(n);
return (s);
}
이것은 인수에
size_t ft_uintlen(unsigned)
대해 작동 하는 새로운 함수를 사용합니다
unsigned
.-------------------
오버플로 방지 메커니즘에 문제가있을 수 있습니다.
x
type
int
을 사용
n
하여 유형 을 할당하려고 합니다
long int
. 그러나 사양은 유형
long int
이 다음보다 큰 값 범위를 처리 할 수 있음을 보장하지 않습니다
int
. 더 많은 정보는
"Long Vs. Int"
에서 찾을 수 있습니다 .컴파일러가 지원하는 경우
long long int
유형을 사용하십시오
n
. 귀하의 업데이트
ft_intlen
에 기능
int ft_intlen(long long int n)
. 이 경우 전체
int
유형 값 범위 를 처리 하고 다음 행을 제거 할 수 있습니다.
if (x == -2147483648)
return (ft_strdup("-2147483648"));
또한 오류 메시지
did not allocate memory for the int min value
는
시스템 오류 번호
중 하나가 아닙니다 . 특히 어떤 이유로 든 디버깅 할 수없는 경우 애플리케이션에 더 많은 로그인을 추가해야합니다.
errno
각 시스템 기능 호출을 확인하십시오 . 예 :
char* errmsg;
// Other code skipped here
if (!(s = (char*)malloc(sizeof(char) * len)))
{
errmsg = strerror(errno); // Use strerror_s if possible
printf("Malloc error: %s\n", errmsg);
return (NULL);
}
-------------------
의심되는 순서대로 잠재적 인 코드 오류 :
ft_strdup()
그 코드는 "int min value"로 호출되고 오류가 발생합니다.- 다양한 기능이 부족한 프로토 타입. 특히
ft_strdup()/strdup()
. - 호출 / 테스트 코드에 결함이 있습니다.
- "int min value"가 -2147483648보다 큽니다. (사용하는 것이 좋습니다
INT_MIN
.) ft_intlen(n)
잘못 코딩되고 반환 된INT_MAX
다음 코드가 시도합니다malloc(INT_MIN)
.int/long
둘 다 64 비트. 이것은 첫 번째s[len - 1] = (n % 10) + '0';
를INT_MIN
.
그렇지
INT_MIN
않고 값이 -2147483648이면
ft_itoa(int x)
괜찮습니다.
OP는 "... strdup은 문자열을 할당하고, ft_intlen은 문자열의 길이를 반환하며, 둘 다 테스트 케이스를 통과합니다. – franklinexpress Oct 8 at 7:52"테스트 케이스를 통과한다고해서 정의되지 않은 동작을 호출하지 않고 작동한다는 의미는 아닙니다. 베스트 게시하려면
ft_intlen()
,
ft_strdup()
및 검토를위한 테스트 장치.
이식 가능한
구현 후보 .
int/long
크기 또는 2의 보수 에 의존하지 않습니다 . 너무 많은 가용성을 희생하지 않고 코드 가 8이라고 가정 할 수 있는 것
<limits.h>
외에는 필요 하지 않습니다. C89 / 99 / 11에서 작동합니다.
CHAR_BIT
// Buffer size needed to decimal print any `int`
// '-' + Ceiling(value bit size * log10(2)) + \0
#define INT_STR_SIZE (1 + ((CHAR_BIT*sizeof(int) - 1)/3 + 1) + 1)
char *ft_itoa(int x) {
char buf[INT_STR_SIZE];
char *s = buf + sizeof buf - 1; // Set to end of buffer
*s = '\0';
int n = x; // no need for wider types like long
if (n > 0) {
// fold positive numbers to negative ones
// This avoids the special code for `INT_MIN` and need for wider types
n = -n;
}
// Using a do loop avoids special code for `x==0`
do {
// Use `div()` rather than / % in case we are using C89.
// / % has implementation defined results for negative arguments.
div_t qr = div(n, 10);
*--s = (char) ('0' - qr.rem); // Form digit from negative .rem
n = qr.quot;
} while (n);
if (x < 0) {
*--s = '-';
}
// Double check ft_strdup() is coded correctly
// Insure calling code frees the buffer when done.
return ft_strdup(s);
}
-------------------
당신이 준 코드는 OsX에서 컴파일되고 작동하지만, 내 자신
ft_stdup
과
ft_intlen
. 따라서 코드를 보여 주거나 오류를 확인할 수 있습니다. 몇 가지 테스트를 수행했습니다 (2147483647, -2147483648 포함). 잘 작동합니다.어쨌든, 라인 :
if (x == -2147483648)
return (ft_strdup("-2147483648"));
어떤 종류의 작업을 수행하기 전에
x
값을
long long
변수 (
Art
)에 복사하는 한 쓸모가 없습니다 . 따라서 포함 할 필요가 없습니다
types.h
(악명 높은 물랑이는 -42를주지 않음).OsX에서는
long
값 에서도 작동 하지만 휴대용 안전하지 않습니다.-------------------
다음을 사용하십시오.
INT_MIN
대신에:
-2147483648
테스트에서 :
if (x == INT_MIN)
return (ft_strdup("-2147483648"));
그 이유는 일부 컴파일러가 해당 숫자를 이해하는 데 문제가있을 수 있기 때문입니다.표준 C 라이브러리
limits.h는
일반적으로 다음과 같이 정의합니다.
#define INT_MIN (-INT_MAX - 1)
이 문제를 피하기 위해.
출처
https://stackoverflow.com/questions/39929982