MFC에서 CString을 int로 변환하기: _ttoi부터 안전한 파싱까지 완벽 정리

Prompt Architect 편집팀 · 2026-06-18 · 7분

TL;DR — MFC/C++ 환경에서 CString 문자열을 정수(int)로 변환하는 방법을 _ttoi, _tstoi64, StrToInt 등으로 비교하고, 유니코드 대응과 에러 처리, 역변환까지 실무 관점에서 정리합니다.

윈도우 데스크톱 애플리케이션을 MFC로 개발하다 보면, 에디트 컨트롤이나 콤보박스에서 받아온 텍스트를 숫자로 다뤄야 하는 순간이 반드시 찾아옵니다. 사용자가 입력한 "1234"라는 문자열은 화면에서는 숫자처럼 보이지만, 프로그램 입장에서는 그저 CString 객체일 뿐입니다. 이걸 더하거나 비교하려면 결국 int로 바꿔야 하죠.

이 글에서는 MFC의 CString을 정수형으로 변환하는 여러 방법을 정리하고, 단순한 한 줄 코드 너머에 숨어 있는 유니코드 대응, 예외 상황 처리, 그리고 역방향(숫자 → 문자열) 변환까지 실무에서 바로 쓸 수 있게 다룹니다.

1. 왜 CString을 int로 바꿔야 할까

CString은 MFC와 ATL이 제공하는 문자열 클래스로, 내부적으로 문자 배열을 관리하며 길이 계산이나 부분 추출 같은 편의 기능을 제공합니다. 하지만 문자열은 어디까지나 "글자의 나열"입니다. 다음 코드는 의도대로 동작하지 않습니다.

CString priceText = _T("1500");
int total = priceText + 500;   // 컴파일 에러 또는 의도와 다른 결과

문자열과 정수는 서로 다른 타입이므로, 산술 연산을 하려면 명시적으로 숫자로 바꿔야 합니다. 바로 이 변환이 오늘의 주제입니다.

2. 가장 기본: _ttoi() 한 줄 변환

가장 널리 쓰이는 방법은 _ttoi() 함수입니다. CString을 받아 정수로 돌려줍니다.

CString quantityText = _T("1234");   // 사용자 입력 등에서 받은 문자열
int quantity = _ttoi(quantityText);  // 정수 1234로 변환

// 변환 결과 확인
if (quantity == 1234) {
    // 정상적으로 변환됨
}

CString은 내부 문자 버퍼를 가리키는 변환 연산자를 제공하기 때문에, _ttoi()에 객체를 그대로 넘겨도 자동으로 문자열 포인터로 변환됩니다. 별도로 GetString()을 호출하지 않아도 동작하는 이유가 여기에 있습니다.

3. 유니코드/멀티바이트 빌드를 모두 지원하는 매크로의 정체

_ttoi의 앞부분 _t는 "텍스트 제너릭(text generic)" 매크로를 뜻합니다. 프로젝트 설정에 따라 컴파일 시점에 다른 함수로 치환됩니다.

빌드 설정 실제로 호출되는 함수
멀티바이트(MBCS) atoi()
유니코드(Unicode) _wtoi()

_ttoi() 하나만 써두면, 프로젝트를 유니코드로 빌드하든 멀티바이트로 빌드하든 같은 코드가 그대로 동작합니다. 요즘 윈도우 프로젝트는 대부분 유니코드가 기본값이므로, 문자열 리터럴에 _T()를 감싸고 제너릭 매크로를 쓰는 습관을 들이는 편이 안전합니다.

// 권장: 어떤 빌드 설정에서도 안전
int value = _ttoi(_T("42"));

// 비권장: 유니코드 빌드에서 깨질 수 있음
int risky = atoi("42");   // 유니코드 프로젝트에서 타입 불일치

4. 더 큰 숫자가 필요할 때: 64비트와 long

int의 표현 범위는 보통 약 ±21억(2,147,483,647)입니다. 주문 번호나 타임스탬프처럼 더 큰 값을 다뤄야 한다면 64비트 변환 함수를 써야 합니다.

CString bigNumberText = _T("9000000000");   // int 범위를 넘는 값

// 64비트 정수로 변환
__int64 bigValue = _ttoi64(bigNumberText);

// long 타입으로 변환이 필요할 때
long longValue = _ttol(_T("100000"));

_ttoi64()는 유니코드 빌드에서 _wtoi64(), 멀티바이트에서 _atoi64()로 치환됩니다. 값의 크기를 미리 가늠해 두고 자료형을 선택하면 오버플로로 인한 음수 발생 같은 버그를 예방할 수 있습니다.

5. 변환 실패를 안전하게 다루기

_ttoi()의 가장 큰 함정은 변환에 실패해도 예외를 던지지 않고 그냥 0을 반환한다는 점입니다.

int a = _ttoi(_T("abc"));    // 0 반환 (숫자가 아님)
int b = _ttoi(_T("0"));      // 0 반환 (실제 입력값이 0)

위에서 ab는 똑같이 0이지만 의미는 완전히 다릅니다. 사용자가 실제로 0을 입력한 것인지, 아니면 잘못된 문자열이라 변환이 실패한 것인지 구분할 수 없습니다. 입력 검증이 중요한 화면이라면 변환 전에 형식을 확인하는 것이 좋습니다.

CString input = _T("12a3");
bool isValid = true;

// 모든 문자가 숫자인지 직접 검사
for (int i = 0; i < input.GetLength(); i++) {
    if (!_istdigit(input[i])) {   // 유니코드 대응 숫자 판별
        isValid = false;
        break;
    }
}

int result = isValid ? _ttoi(input) : -1;   // 실패 시 사전 정의한 값

더 엄밀하게 변환 끝 지점까지 확인하고 싶다면 _tcstol()(C 표준 strtol의 제너릭 버전)을 쓰는 방법도 있습니다. 이 함수는 변환이 멈춘 위치를 포인터로 돌려주므로, 문자열 전체가 숫자였는지 끝까지 검증할 수 있습니다.

CString text = _T("789xyz");
LPTSTR endPtr = nullptr;

long parsed = _tcstol(text, &endPtr, 10);   // 10진수로 파싱
// endPtr가 문자열 끝(널 문자)을 가리키지 않으면, 뒤에 숫자가 아닌 문자가 남은 것
if (*endPtr != _T('\0')) {
    // "789xyz"처럼 잘못된 입력 처리
}

6. 반대 방향: int를 CString으로

화면에 숫자를 다시 보여주려면 역변환도 필요합니다. CString::Format() 메서드가 가장 직관적입니다.

int score = 100;
CString display;
display.Format(_T("%d"), score);   // "100" 이라는 문자열 생성

// 여러 값을 합쳐서 표시할 수도 있음
int win = 7, lose = 3;
CString record;
record.Format(_T("%d승 %d패"), win, lose);   // "7승 3패"

Format()은 C의 printf 서식 지정자를 그대로 사용합니다. %d는 정수, %lld는 64비트 정수, %x는 16진수를 의미합니다. 서식 문자열에도 반드시 _T()를 감싸야 유니코드 빌드에서 안전합니다.

7. 자주 하는 실수와 엣지 케이스

  • 앞뒤 공백: _T(" 42 ")처럼 공백이 섞이면 앞쪽 공백은 무시되지만 뒤쪽 비숫자 문자에서 변환이 멈춥니다. 입력 전에 Trim()으로 정리하는 습관이 좋습니다.
  • 부호 처리: _ttoi(_T("-25"))는 정상적으로 -25를 반환합니다. 음수 입력을 허용할지 정책을 정해두세요.
  • 천 단위 콤마: "1,000" 같은 형식은 콤마에서 변환이 끊겨 1만 얻게 됩니다. 콤마를 먼저 Remove(_T(','))로 제거해야 합니다.
  • 빈 문자열: _ttoi(_T(""))는 0을 반환합니다. 5번 항목과 마찬가지로 "진짜 0"과 구분되지 않으니 빈 입력은 별도로 거르세요.
  • 선행 0: "007"은 7로 변환됩니다. 다만 08이나 09처럼 _tcstol에 진법을 0(자동 감지)으로 넘기면 8진수로 오해할 수 있으니, 10진수 고정이 필요하면 세 번째 인자에 명시적으로 10을 넣으세요.

8. 요약

MFC에서 CString을 정수로 바꾸는 핵심은 다음과 같습니다.

  • 가장 간단한 변환은 _ttoi(). 유니코드/멀티바이트 빌드 모두에서 안전합니다.
  • 큰 값은 _ttoi64()(64비트), _ttol()(long)을 사용합니다.
  • _ttoi()는 실패해도 0을 반환하므로, 입력 검증이 중요하면 _istdigit 루프나 _tcstol로 끝까지 검사하세요.
  • 역변환은 CString::Format(_T("%d"), num)이 표준입니다.
  • 문자열 리터럴은 항상 _T()로 감싸는 습관을 들이세요.

AI에게 물어볼 때 (프롬프트 팁)

이런 변환 코드를 AI에게 물을 때, 막연히 "CString을 int로 바꿔줘"라고 하면 빌드 설정이나 예외 처리를 빠뜨린 답을 받기 쉽습니다. 맥락과 제약을 함께 주면 실무에 바로 쓸 수 있는 코드가 나옵니다.

프롬프트 예시 1 — 환경과 제약 명시

MFC(C++) 유니코드 빌드 환경입니다. 에디트 컨트롤에서 받은 CString을
int로 변환하되, 숫자가 아닌 입력이 들어오면 변환 실패를 감지할 수 있게
하고 싶습니다. _ttoi 대신 끝까지 검증하는 방식으로 코드와 이유를 설명해 주세요.

프롬프트 예시 2 — 비교와 트레이드오프 요청

CString을 정수로 바꾸는 _ttoi, _tcstol, StrToInt를 표로 비교해 주세요.
각 함수의 변환 실패 시 동작, 64비트 지원 여부, 오버플로 처리를
기준으로 정리하고, 사용자 입력 검증 화면에는 무엇을 추천할지 알려 주세요.

프롬프트 예시 3 — 코드 리뷰 관점

다음 MFC 코드에서 CString -> int 변환 부분의 잠재적 버그를 찾아 주세요.
빈 입력, 공백, 천 단위 콤마, int 오버플로 관점에서 점검하고
수정안을 제시해 주세요.

[여기에 본인 코드 붙여넣기]

이처럼 "환경, 제약, 비교 기준, 검증 관점"을 프롬프트에 명확히 담으면 AI의 답변 품질이 크게 달라집니다. 좋은 코드를 얻는 출발점은 결국 좋은 질문이며, 이것이 바로 프롬프트 설계의 힘입니다. 더 효과적인 질문을 설계하고 싶다면 Prompt Architect의 프롬프트 분석 도구로 본인 질문을 점검해 보세요.