프로그램을 작성하다 보면 변수(Variable)와 반대로 절대 변해서는 안 되는 값들이 존재한다. 원주율(Pi)이나 데이터 버퍼의 최대 크기 같은 것들이다. 오늘은 이런 데이터들을 안전하게 잠가두는 방법과, 필요에 따라 데이터의 형태를 바꾸는 '형변환(Type Conversion)'에 대해 정리해 본다. 특히 형변환 파트에서는 C 언어와는 확연히 달라진 C++만의 모던한 문법이 등장한다.
1. 절대 바뀔 수 없는 수, 상수와 const 제한자
C 언어에서는 상수를 정의할 때 주로 파일 최상단에 매크로를 이용해 #define PI 3.14 형태로 선언하곤 했다. 하지만 C++에서는 이 방식보다 const 제한자를 사용하는 것을 훨씬 권장한다.
#include <iostream>
using namespace std;
int main() {
// const 제한자를 사용한 상수 선언
const float PIE = 3.1415926535;
int r = 3;
float s = r * r * PIE; // 원의 넓이 계산
// PIE = 3.14; // 에러 발생! const로 잠긴 변수는 값을 덮어쓸 수 없다.
return 0;
}
🤔 왜 #define 대신 const를 쓸까? #define은 컴파일러가 코드를 읽기도 전에 단순하게 텍스트를 복사-붙여넣기 해버리는 방식이다. 반면 const는 float이라는 명확한 '자료형(Type)'을 가지며, 변수처럼 특정 범위(Scope) 안에서만 유효하도록 생명 주기를 통제할 수 있다. 디버깅을 할 때도 메모리에 명확히 추적되기 때문에 훨씬 안전하고 객체지향적인 방식이다.
2. 데이터형 변환 (Type Conversion)의 3가지 상황
프로그램을 돌리다 보면 서로 다른 자료형이 섞이거나 억지로 맞춰야 하는 상황이 빈번하게 발생한다. 크게 세 가지 경우가 있다.
- 대입할 때: 특정 데이터형 변수에 다른 데이터형의 값을 넣을 때 (int a = 3.14;)
- 연산할 때: 수식 안에서 정수와 실수를 혼합하여 계산할 때
- 함수 호출 시: 함수가 요구하는 매개변수 타입과 내가 전달하는 값의 타입이 다를 때
이런 상황에서 C++ 컴파일러가 알아서 타입을 맞춰주는 것을 '암시적 형변환(Implicit Conversion)'이라고 한다. 하지만 앞서 살펴봤듯 이는 데이터 손실(소수점 잘림 등)을 유발할 수 있으므로, 개발자가 직접 "이 데이터는 이 타입으로 바꿔라!"라고 명시하는 '강제 형변환(Explicit Conversion)'이 필요하다.
3. C 스타일 형변환 vs C++의 static_cast
문자형(char) 변수 안에 들어있는 알파벳 'M'의 진짜 아스키코드(정수) 번호가 궁금하다고 가정해 보자. 이를 정수형(int)으로 강제 변환해야 한다.
#include <iostream>
using namespace std;
int main() {
char ch = 'M';
// 1. C 스타일의 강제 형변환 (여전히 작동은 한다)
cout << (int)ch << endl; // 출력: 77
cout << int(ch) << endl; // 출력: 77
// 2. 모던 C++ 스타일의 강제 형변환 (권장)
cout << static_cast<int>(ch) << endl; // 출력: 77
return 0;
}
💡 C++에서는 왜 복잡하게 static_cast를 쓸까?
C 언어 스타일인 (int)ch는 아주 강력해서, 논리적으로 아예 말이 안 되는 변환(예: 포인터 주소를 일반 정수로 변환)까지도 억지로 뚫고 지나가 버린다. 이는 나중에 겉잡을 수 없는 치명적인 에러를 낳는다.
반면 C++에서 새롭게 도입된 static_cast<typeName> 연산자는 컴파일 단계에서 "이 형변환이 상식적으로 안전하고 말이 되는 변환인가?"를 한 번 검사해 준다. 만약 위험한 변환이라면 얄짤없이 컴파일 에러를 뱉어내어 실수를 막아준다.
게다가 코드가 길어졌을 때 (int) 같은 괄호는 검색하기도 어렵지만, static_cast는 코드상에서 형변환이 일어난 위치를 명확하게 검색하고 식별할 수 있다는 엄청난 장점이 있다.
'C++' 카테고리의 다른 글
| 6. C++의 진입장벽 포인터(Pointer)와 동적 할당: 도대체 왜 쓰는 걸까? (0) | 2026.03.03 |
|---|---|
| 4. 복합 데이터형: 깐깐한 배열(Array) 규칙부터 구원자 'string'까지 (0) | 2026.02.27 |
| 2. 크기 제한: 기본 자료형과 climits (0) | 2026.02.26 |
| 1. 왜 C++인가? 기본 구조부터 변수와 메모리의 이해까지 (0) | 2026.02.24 |