Menu

C 언어 문자열을 int로: atoi, strtol, 그리고 숫자를 문자열로

C에서 텍스트와 숫자 사이를 오가는 법: atoi가 오류를 알릴 수 없는 이유, endptr과 errno로 strtol과 strtod를 제대로 쓰는 법, snprintf로 숫자를 문자열로 만들기, 그리고 '0'을 이용한 한 자리 요령.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

텍스트는 사용자와 파일, 명령줄에서 문자로 도착합니다. "42"는 세 바이트 - '4', '2', '\0' - 이고, 변환하기 전까지는 그 안의 어떤 것도 숫자 42가 아닙니다. C는 두 세대의 변환 함수를 제공합니다. 짧고 오래되어 오류를 알릴 수 없는 것들과, 더 길지만 알릴 수 있는 것들입니다. 이 페이지는 둘 다 보여 주고 실제 프로그램이 왜 두 번째 집합을 쓰는지 설명합니다.

오래된 가족: atoi, atol, atof

이름 그대로 읽힙니다. ASCII를 int로, long으로, double로. 인자 하나, 결과 하나입니다.

앞쪽 공백은 건너뛰고, 선택적인 부호를 읽고, 숫자를 소비하고, 그 뒤는 전부 무시합니다. 입력이 잘못되기 전까지는 편리합니다.

셋 다 0을 출력합니다. 반환 코드도, 플래그도, "그게 됐나요?"라고 물을 방법도 없습니다. 그리고 int를 넘치는 값은 보고되는 오류가 아니라 미정의 동작입니다. 장난감 프로그램에 하드코딩한 리터럴이라면 참아 줄 만합니다. 사람이나 파일이 줄 수 있는 것이라면 조용한 버그 생성기입니다.

올바른 도구: strtol

strtol(string to long)은 같은 변환에 무슨 일이 있었는지 알리는 통로 둘이 붙은 것입니다.

long strtol(const char *text, char **endptr, int base);

endptr은 함수가 소비하지 않은 첫 문자로 설정됩니다. base는 진법입니다. 10을 쓰거나, 리터럴 자신의 접두사가 결정하게 하려면 0을 쓰세요(16진수는 0x, 8진수는 앞의 0).

endptr을 읽으면 atoi가 답할 수 없는 질문에 답할 수 있습니다.

  • end == input이면 아무것도 변환되지 않았다는 뜻입니다. 텍스트가 숫자로 시작하지 않았습니다.
  • *end != '\0'이면 뒤에 남은 내용이 있다는 뜻입니다. 그것이 오류인지는 여러분의 판단입니다. "42 apples"를 파싱할 때는 괜찮고, 줄 전체가 숫자여야 했다면 문제입니다.

오버플로는 errno를 통해 따로 보고됩니다. 완전하고 올바른 관용구는 한 번 써 두고 재사용할 만합니다.

세부 사항 셋이 이것을 올바르게 만듭니다. 호출 전의 errno = 0이 중요한 이유는 라이브러리가 errno설정만 할 뿐 절대 지우지 않기 때문입니다. 앞선 호출이 남긴 값이 이번 호출의 실패로 읽힐 수 있습니다. strtolint보다 넓을 수 있는 long을 반환하므로, INT_MIN/INT_MAX에 대한 범위 검사는 ERANGE와 별개입니다. 그리고 성공 여부를 상태로 반환하면서 값을 포인터로 전달하는 것이, C 함수가 "값이거나 실패"를 알리는 방식입니다. 반환값 하나가 두 일을 다 할 수는 없으니까요.

strtoul은 부호 없는 대응물이고, strtoll/strtoulllong long을 다룹니다.

다른 진법

진법 16은 16진수를 읽고, 진법 0은 접두사를 보고 스스로 결정합니다.

진법 0은 한 가지 특정한 경우에 함정입니다. "012"처럼 0으로 채워진 십진수가 8진수로 읽혀 10이 나옵니다. 입력이 십진수라면 10을 명시하세요.

부동소수점: strtod

strtoddouble을 위한 같은 모양이고, atofatoi와 같은 결함을 가지고 있습니다.

strtod는 과학적 표기법("1.5e3"), 16진 부동소수점, 그리고 "inf""nan"이라는 낱말도 받아들입니다. 로케일이 소수점 구분자에 영향을 주는데, 다른 곳에서 쓰인 파일을 파싱하는 사람들을 놀라게 합니다. 기본 "C" 로케일에서 구분자는 항상 점입니다.

숫자를 텍스트로: snprintf

반대 방향에서는 snprintf가 표준적인 답입니다. 지정한 크기까지만 쓰고, 항상 종료 문자를 넣으며, 전체 결과에 필요했을 길이를 반환합니다.

반환값이 잘림 검사입니다. 버퍼 크기 이상이면 텍스트가 들어가지 않은 것입니다.

손대지 말아야 할 것 둘. itoa는 표준 C의 일부가 아니므로 그것을 쓴 코드는 어디서나 컴파일되지 않습니다. 그리고 sprintf는 크기 제한이 없는 snprintf라서, 불평 없이 버퍼 끝을 넘어 씁니다.

문자 하나와 '0'

숫자 문자 '0'부터 '9'까지는 연속임이 보장되므로, 단순한 뺄셈으로 숫자 문자와 그 값 사이를 오갈 수 있습니다.

이렇게 동작하는 것은 숫자뿐입니다. 알파벳은 연속일 필요가 없으므로 c - 'a'는 이식성 있는 문자 산술이 아닙니다. 믿기 전에 isdigit으로 뺄셈을 지키세요.

unsigned char 캐스팅이 필요한 이유는 문자열에서와 같습니다. <ctype.h> 함수들은 음수 인자에 대해 미정의이고, 평범한 char는 부호 있는 타입일 수 있습니다.

어떤 함수를 쓸 것인가

  • 사용자, 파일, argv에서 온 텍스트 → 완전한 검사를 갖춘 strtol / strtod.
  • 직접 쓰고 통제하는 리터럴 → atoi도 받아들일 만합니다. 특별할 것은 없지만요.
  • 버퍼에 숫자 넣기 → snprintf, 그리고 반환값 확인.
  • 숫자 문자 하나 → isdigit 뒤에 '0' 빼기.
  • 절대 금지 → gets, sprintf, itoa.

자주 묻는 질문

C에서 문자열을 int로 어떻게 변환하나요?

strtol(text, &end, 10)이 올바른 답입니다. 값을 반환하고, 소비하지 않은 첫 문자를 end에 넣고, 오버플로를 errno로 알려 줍니다. atoi(text)는 더 짧지만 "0""hello" 둘 다에 대해 0을 반환하며 구별할 방법이 없습니다.

C에서 atoi의 무엇이 문제인가요?

실패를 알릴 수 없습니다. atoi("abc")0을 반환하는데 이는 진짜 0과 구별되지 않고, 오버플로는 보고되는 오류가 아니라 미정의 동작입니다. 텍스트가 사용자나 파일, 명령줄 인자에서 왔다면 언제나 strtol을 쓰세요.

C에서 int를 문자열로 어떻게 변환하나요?

snprintf(buf, sizeof buf, "%d", n)을 씁니다. 표준이고, 버퍼 크기로 제한되며, 전체 결과에 필요했던 문자 수를 반환합니다. 반환값이 sizeof buf 이상이면 텍스트가 잘렸다는 뜻입니다. itoa는 표준 C가 아닙니다.

C에서 문자 '7'을 숫자 7로 어떻게 바꾸나요?

'0'을 빼세요. int digit = c - '0';입니다. 숫자 문자들은 모든 C 문자 집합에서 연속이므로 이 뺄셈이 0에서 9를 줍니다. 다른 문자에는 의미가 없으니 먼저 isdigit((unsigned char)c)로 지키세요.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기