대부분의 컴퓨터 언어에서 16진수 문자열을 숫자로 변환해주는 HEX2DEC() 함수를 지원한다.
엑셀이나 매틀랩 등은 물론이고, PHP에서도 지원된다.
윈도우10에 내장된 계산기에선 더욱 손쉽게 이를 처리해준다.
그런데, 막상 C언어에서 이를 사용하려면 아주 쉽게는 되지 않는다.
기능이 없는 것은 아닌데, 위에서 언급한 언어/환경에 비해선 뭔가 손이 좀 더 간다.
1. sscanf()
물론, C언어의 표준 함수인 sscanf() 함수로 이를 처리할 수 있다.
깔끔하게 처리가 가능하다.
char hex_text[] = "1A2B";
int val;
sscanf(hex_text, "%X", &val);
printf("%d\n", val);
2. 직접 작성-1
그런데, 여러가지 이유로 직접 이 기능을 구현해야 할 필요가 있다.
좀 더 빠른 동작의 함수가 필요하거나, 마이컴에서 좀 더 작은 실행파일이 필요하거나 등등.
대략 아래와 같은 방식으로 작성할 것이다.
long hex2dec(char * a) {
char c;
long ret = 0;
while (*a) {
c = *a++;
if (c >= '0' && c <= '9') {
c -= '0';
} else if (c >= 'a' && c <= 'f') {
c = (c - 'a') + 10;
} else if (c >= 'A' && c <= 'F') {
c = (c - 'A') + 10;
} else {
return ret;
}
ret = (ret << 4) + c;
}
return ret;
}
이 코드는 잘 동작하지만, 뭔가 좀 찝찝한 구석이 있다.
비교 연산자가 너무 많이 사용되는 것.
물론, 요즘 컴퓨팅 환경이 이 정도의 비교 구문은 손쉽게 처리하긴 하지만, 뭔가 아쉽다.
3. 직접 작성-2
최근 메모장2 업데이트 중 Simplify hexadecimal number conversions이란 내용이 있었다.
위의 코드와 유사한 코드를 대폭 최적화한 내용이었다.
이 코드의 골자는 두 가지다.
- signed와 unsigned의 차이를 이용해서 비교 구문을 줄임
- or(|) 연산자를 활용해서 대소문자를 한번에 처리
이 내용을 적용한 코드는 다음과 같다.
long hex2dec(char * a) {
char c;
unsigned char diff;
long ret = 0;
while (*a) {
c = *a++;
diff = c - '0';
if (diff > 9) {
diff = (c | 0x20) - 'a';
if (diff > 5) {
return ret;
}
diff += 10;
}
ret = (ret << 4) + diff;
}
return ret;
}