문자열을 정수로 변환하는 데 sscanf 또는 atoi의 차이점은 무엇입니까?
gcc 4.4.4 c89
문자열을 정수 값으로 변환하는 것이 더 낫습니다.
atoi와 sscanf의 두 가지 다른 방법을 시도했습니다. 둘 다 예상대로 작동합니다.
char digits[3] = "34";
int device_num = 0;
if(sscanf(digits, "%d", &device_num) == EOF) {
fprintf(stderr, "WARNING: Incorrect value for device\n");
return FALSE;
}
또는 atoi 사용
device_num = atoi(digits);
오류를 확인할 수 있으므로 sscanf가 더 좋을 것이라고 생각했습니다. 그러나 atoi는 어떤 검사도하지 않습니다.
3 가지 선택이 있습니다.
atoi
성능이 중요한 코드에서 사용하는 경우 아마도 가장 빠르지 만 오류보고는 없습니다. 문자열이 정수로 시작하지 않으면 0을 반환합니다. 문자열이 정수 뒤에 정크를 포함하면 초기 부분을 변환하고 나머지는 무시합니다. 숫자가 너무 커서에 맞지 int
않으면 동작이 지정되지 않습니다.
sscanf
일부 오류보고 및 저장할 유형 (의 서명 된 / 서명되지 않은 버전 char/short/int/long/long long/size_t/ptrdiff_t/intmax_t
)에 대해 많은 유연성이 있습니다.
반환 값은 성공한 변환 수이므로 "%d"
문자열이 정수로 시작하지 않으면 검색 은 0을 반환합니다. "%d%n"
다른 변수에서 읽은 정수 뒤의 첫 번째 문자의 인덱스를 저장하는 데 사용할 수 있으므로 전체 문자열이 변환되었는지 또는 나중에 정크가 있는지 확인할 수 있습니다. 그러나와 같이 atoi
정수 오버플로에 대한 동작은 지정되지 않습니다.
strtol
그리고 가족
errno
전화를 걸기 전에 0으로 설정 한 경우 강력한 오류보고 . 반환 값은 오버플로에 지정되며 errno
설정됩니다. 당신은 2에서 36까지 숫자 기반을 선택하거나,에 기지로 0을 지정할 수 있습니다 최고의 자동 해석 0x
및 0
진수와 8 진수로 각각. 변환 할 유형의 선택은 long/long long/intmax_t
.
더 작은 유형이 필요한 경우 항상 결과를 임시 long
또는 unsigned long
변수 에 저장하고 오버플로를 직접 확인할 수 있습니다.
이러한 함수는 포인터 인수에 대한 포인터를 사용하므로 변환 된 정수 다음의 첫 번째 문자에 대한 포인터도 무료로 얻습니다. 따라서 전체 문자열이 정수인지 여부를 알 수 있거나 필요한 경우 문자열의 후속 데이터를 구문 분석 할 수 있습니다.
개인적 strtol
으로 대부분의 목적으로 가족을 추천 합니다. 빠르고 더러운 일을하고 있다면 atoi가 당신의 요구를 충족시킬 수 있습니다.
제쳐두고 때로는 선행 공백, 기호 등이 허용되지 않아야하는 숫자를 구문 분석해야하는 경우가 있습니다. 이 경우에는 for 루프를 롤링하는 것이 매우 쉽습니다.
for (x=0; (unsigned)*s-'0'<10; s++)
x=10*x+(*s-'0');
또는 다음을 사용할 수 있습니다 (견고성을 위해).
if (isdigit(*s))
x=strtol(s, &s, 10);
else /* error */
*scanf()
함수 군은 변환 된 값의 수를 반환합니다. 따라서 sscanf()
케이스에서 1을 반환 하는지 확인해야 합니다. EOF
"입력 실패"에 대해 ssacnf()
반환 EOF
됩니다. 이는를 반환하지 않음 을 의미합니다 .
의 경우 sscanf()
함수는 형식 문자열을 구문 분석 한 다음 정수를 디코딩해야합니다. atoi()
그 오버 헤드가 없습니다. 둘 다 범위를 벗어난 값으로 인해 정의되지 않은 동작이 발생한다는 문제가 있습니다.
더 나은 오류 감지 및 검사를 제공 하는 strtol()
또는 strtoul()
기능을 사용해야합니다 . 또한 전체 문자열이 소비되었는지 여부도 알려줍니다.
당신이 원한다면 int
, 당신은 항상 사용할 수 있습니다 strtol()
, 다음이 사이에 놓여 있는지 확인하기 위해 반환 값을 확인 INT_MIN
하고 INT_MAX
.
@R .. 호출 errno
에서 오류 감지 를 확인하는 것으로 는 충분하지 않다고 생각합니다 strtol
.
long strtol (const char *String, char **EndPointer, int Base)
또한 EndPointer
오류 를 확인해야 합니다.
간결성을 위해 R .. 및 PickBoy 답변 결합
long strtol (const char *String, char **EndPointer, int Base)
// examples
strtol(s, NULL, 10);
strtol(s, &s, 10);
유효하지 않은 문자열 입력 또는 범위 문제에 대한 우려가 없으면 가장 간단한 방법을 사용하십시오. atoi()
그렇지 않으면 최상의 오류 / 범위 감지 방법은 atoi()
, 또는 sscanf()
. 이 좋은 대답은 모든 준비 사항과 오류 검사의 부족 atoi()
과 일부 에 오류 검사를 sscanf()
.
strtol()
문자열을로 변환 할 때 가장 엄격한 함수입니다 int
. 그러나 그것은 시작에 불과합니다. 다음은 적절한 사용법을 보여주는 자세한 예와 수락 된 답변 이후에이 답변에 대한 이유입니다 .
// Over-simplified use
int strtoi(const char *nptr) {
int i = (int) strtol(nptr, (char **)NULL, 10);
return i;
}
이것은 유사 atoi()
하며의 오류 감지 기능을 사용하지 strtol()
않습니다.
를 완전히 사용하려면 strtol()
고려해야 할 다양한 기능이 있습니다.
Detection of no conversion: Examples:
"xyz"
, or""
or"--0"
? In these cases,endptr
will matchnptr
.char *endptr; int i = (int)strtol(nptr, &endptr, 10); if (nptr == endptr) return FAIL_NO_CONVERT;
Should the whole string convert or just the leading portion: Is
"123xyz"
OK?char *endptr; int i = (int)strtol(nptr, &endptr, 10); if (*endptr != '\0') return FAIL_EXTRA_JUNK;
Detect if value was so big, the the result is not representable as a
long
like"999999999999999999999999999999"
.errno = 0; long L = strtol(nptr, &endptr, 10); if (errno == ERANGE) return FAIL_OVERFLOW;
Detect if the value was outside the range of than
int
, but notlong
. Ifint
andlong
have the same range, this test is not needed.long L = strtol(nptr, &endptr, 10); if (L < INT_MIN || L > INT_MAX) return FAIL_INT_OVERFLOW;
Some implementations go beyond the C standard and set
errno
for additional reasons such as errno to EINVAL in case no conversion was performed orEINVAL
The value of the Base parameter is not valid.. The best time to test for theseerrno
values is implementation dependent.
Putting this all together: (Adjust to your needs)
#include <errno.h>
#include <stdlib.h>
int strtoi(const char *nptr, int *error_code) {
char *endptr;
errno = 0;
long i = strtol(nptr, &endptr, 10);
#if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
if (errno == ERANGE || i > INT_MAX || i < INT_MIN) {
errno = ERANGE;
i = i > 0 : INT_MAX : INT_MIN;
*error_code = FAIL_INT_OVERFLOW;
}
#else
if (errno == ERANGE) {
*error_code = FAIL_OVERFLOW;
}
#endif
else if (endptr == nptr) {
*error_code = FAIL_NO_CONVERT;
} else if (*endptr != '\0') {
*error_code = FAIL_EXTRA_JUNK;
} else if (errno) {
*error_code = FAIL_IMPLEMENTATION_REASON;
}
return (int) i;
}
Note: All functions mentioned allow leading spaces, an optional leading sign character and are affected by locale change. Additional code is required for a more restrictive conversion.
Note: Non-OP title change skewed emphasis. This answer applies better to original title "convert string to integer sscanf or atoi"
If user enters 34abc and you pass them to atoi it will return 34. If you want to validate the value entered then you have to use isdigit on the entered string iteratively
'IT박스' 카테고리의 다른 글
상속이있는 @Data 주석 lombok에서 equals / hashCode 경고 (0) | 2020.11.24 |
---|---|
Android Studio build.gradle 경고 메시지 (0) | 2020.11.24 |
AUTO_INCREMENT를 기존 열에 추가하는 방법은 무엇입니까? (0) | 2020.11.24 |
비정규 부동 소수점 숫자는 무엇입니까? (0) | 2020.11.24 |
.push () 메서드를 통해 객체에 항목 추가 (0) | 2020.11.23 |