C 언어에서 dec/hex 숫자를 입력으로 받기
C 언어에서 dec/hex 숫자를 문자열로 입력으로 받아서 처리할 때의 팁을 공유한다.
dec/hex 기본 처리
C에서 10진수/16진수 숫자를 문자열로 입력받아서 정수값으로 변환할 때 strtoul()
함수를 사용하면 되는 것은 C 프로그래머라면 모두가 익히 아는 사실이다.
그런데, 일부 개발자들은 이 함수에서 3번째 파라미터인 base에서 10, 16 등만 유효한 값으로 알고 있는 사람들은 아래 코드 예와 같이 10진수, 16진수를 각각 처리하는 경우가 있다.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *value_str;
unsigned int value;
if (argc < 2)
{
return 1;
}
value_str = argv[1];
if (value_str[0] == '0' && value_str[1] == 'x')
{
value = strtoul(value_str, NULL, 16);
}
else
{
value = strtoul(value_str, NULL, 10);
}
printf("value: %d(0x%x)\n", value, value);
return 0;
}
개선한 dec/hex 처리
그런데 strtoul()
함수의 3번째 파라미터인 base 값으로는 10, 16 등 뿐만 아니라, 0
도 가능하다. 특히 0
으로 세팅할 경우에는 base를 자동으로 판단하므로, 위 코드는 간단히 아래와 같이 작성될 수 있다.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *value_str;
unsigned int value;
if (argc < 2)
{
return 1;
}
value_str = argv[1];
value = strtoul(value_str, NULL, 0);
printf("value: %d(0x%x)\n", value, value);
return 0;
}
dec/hex 에러 처리
그런데 위 코드들의 문제는 올바르지 않은 숫자 문자열이 입력된 경우의 처리를 못한다는 것이다.
예를 들어 숫자 뒤에 틀린 알파벳이 온 경우는 아래 예와 같이 올바른 숫자까지의 값이 얻어진다.
$ ./test 256wrong
value: 256(0x100)
$ ./test 0x100wrong
value: 256(0x100)
반면에 만약 틀린 알파벳으로 시작하면 0이 얻어진다.
보통은 이렇게 잘못 입력된 숫자 문자열인 경우에는 올바르지 않은 숫자로 얻는 것보다는 에러로 처리하는 것이 더 좋은데, 이를 디텍트하려면 strtoul
의 두번째 파라미터인 endptr를 이용하면 된다.
세부적으로 endptr는 아래와 같은 리턴값을 가진다.
- 잘못된 문자가 있는 경우: 첫번째 잘못된 문자의 주소를 가리키고, 값은 해당 문자값을 가짐
- 잘못된 문자가 없는 경우: 입력 문자열의 마지막 문자 다음 주소값을 가리키고, 값은
0
을 가짐
따라서 아래 코드 예와 같이 판단할 수 있다.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *value_str;
unsigned int value;
char *endptr;
if (argc < 2)
{
return 1;
}
value_str = argv[1];
value = strtoul(value_str, &endptr, 0);
if (*endptr != '\0')
{
printf("Input string is wrong\n");
return 1;
}
printf("value: %d(0x%x)\n", value, value);
return 0;
}
위 코드로 테스트해보면 아래 예와 같이 잘못된 문자가 있는 경우에는 기대대로 에러로 처리된다.
$ ./test 256wrong
Input string is wrong
$ ./test 0x100wrong
Input string is wrong
물론 아래 예와 같이 올바로 입력한 경우에는 정상적으로 값을 얻어온다.
$ ./test 100
value: 100(0x64)
$ ./test 0x100
value: 256(0x100)