icon안동민 개발노트

형변환


형변환의 개념

 형변환(Type Conversion)은 하나의 데이터 타입을 다른 데이터 타입으로 변환하는 과정입니다. C++에서 형변환은 크게 두 가지로 나눌 수 있습니다.

  1. 암시적 형변환 (Implicit Type Conversion)
  2. 명시적 형변환 (Explicit Type Conversion)

암시적 형변환

 암시적 형변환은 컴파일러가 자동으로 수행하는 변환입니다. 주로 다음과 같은 경우에 발생합니다.

  1. 대입 연산에서 서로 다른 타입 간 변환
  2. 산술 연산에서 피연산자 간 변환
  3. 함수 호출 시 인자 타입 변환
예제
int i = 10;
double d = i;  // int에서 double로 암시적 변환
 
char c = 'A';
int ascii = c;  // char에서 int로 암시적 변환
 
int x = 5, y = 2;
double result = x / y;  // 결과는 2.0 (정수 나눗셈 후 double로 변환)

명시적 형변환

 명시적 형변환은 프로그래머가 직접 지정하는 변환입니다. C++에서는 여러 가지 방식의 명시적 형변환을 제공합니다.

 C 스타일 캐스트

 C언어에서 사용하던 방식으로, 간단하지만 안전하지 않을 수 있습니다.

double d = 3.14;
int i = (int)d;  // double에서 int로 명시적 변환

 C++ 스타일 캐스트

 C++에서는 더 안전하고 명확한 형변환을 위해 다음 네 가지 캐스트 연산자를 제공합니다.

  1. static_cast
  • 컴파일 시간에 형 검사를 수행
  • 주로 숫자 타입 간 변환에 사용
double d = 3.14;
int i = static_cast<int>(d);
  1. dynamic_cast
  • 주로 클래스의 다형성을 위해 사용
  • 런타임에 형 검사를 수행
class Base { virtual void dummy() {} };
class Derived : public Base { /*...*/ };
Base* base_ptr = new Derived;
Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);
  1. const_cast
  • const 또는 volatile 지정자를 제거
const int* ptr = &value;
int* mutable_ptr = const_cast<int*>(ptr);
  1. reinterpret_cast
  • 포인터 타입 간 변환 등 저수준 변환에 사용
  • 매우 위험할 수 있으므로 주의 필요
int* p = new int(65);
char* ch = reinterpret_cast<char*>(p);

주요 형변환 사례

  1. 정수형 간 변환
short s = 1000;
int i = s;  // 문제 없음
char c = s;  // 데이터 손실 가능성
  1. 부동소수점형 간 변환
float f = 3.14f;
double d = f;  // 문제 없음
f = d;  // 정밀도 손실 가능성
  1. 정수형과 부동소수점형 간 변환
int i = 3;
float f = i;  // 문제 없음
i = f;  // 소수점 이하 손실
  1. 포인터 형변환
int* p_int = new int(65);
char* p_char = reinterpret_cast<char*>(p_int);

형변환의 위험성

  1. 데이터 손실
int large = 1000000;
short small = static_cast<short>(large);  // 오버플로우 발생
  1. 오버플로우 / 언더플로우
unsigned char uc = 255;
uc++;  // 오버플로우: uc는 0이 됨
  1. 부동소수점 정밀도 손실
double d = 0.1 + 0.2;
float f = static_cast<float>(d);  // 정밀도 손실 가능성

안전한 형변환 기법

  1. 범위 체크
#include <limits>
 
template<typename T, typename U>
T safe_cast(U value) {
      if (value > std::numeric_limits<T>::max() || 
         value < std::numeric_limits<T>::min()) {
         throw std::overflow_error("Cast would cause overflow");
      }
      return static_cast<T>(value);
}
  1. numeric_limits 활용
#include <limits>
#include <iostream>
 
int main() {
      std::cout << "int 최대값: " << std::numeric_limits<int>::max() << std::endl;
      std::cout << "float 최소값: " << std::numeric_limits<float>::min() << std::endl;
}

실습

  1. 다양한 형변환 예제
#include <iostream>
 
int main() {
    // 정수형 간 변환
    short s = 1000;
    int i = s;
    long l = i;
    
    std::cout << "short to int: " << i << std::endl;
    std::cout << "int to long: " << l << std::endl;
    
    // 부동소수점형 간 변환
    float f = 3.14f;
    double d = f;
    
    std::cout << "float to double: " << d << std::endl;
    
    // 정수형과 부동소수점형 간 변환
    i = static_cast<int>(f);
    f = i;
    
    std::cout << "float to int: " << i << std::endl;
    std::cout << "int to float: " << f << std::endl;
    
    return 0;
}
  1. 형변환으로 인한 데이터 손실 사례
#include <iostream>
 
int main() {
    int large = 1000000;
    short small = static_cast<short>(large);
    
    std::cout << "Original int: " << large << std::endl;
    std::cout << "Converted to short: " << small << std::endl;
    
    double d = 3.14159265358979323846;
    float f = static_cast<float>(d);
    
    std::cout << "Original double: " << d << std::endl;
    std::cout << "Converted to float: " << f << std::endl;
    
    return 0;
}
  1. static_castdynamic_cast의 차이점
#include <iostream>
 
class Base {
public:
    virtual void print() { std::cout << "Base" << std::endl; }
    virtual ~Base() {}
};
 
class Derived : public Base {
public:
    void print() override { std::cout << "Derived" << std::endl; }
};
 
int main() {
    Base* base_ptr = new Derived();
    
    // static_cast
    Derived* derived_ptr1 = static_cast<Derived*>(base_ptr);
    derived_ptr1->print();  // 안전하지만, 실제 타입 확인 불가
    
    // dynamic_cast
    Derived* derived_ptr2 = dynamic_cast<Derived*>(base_ptr);
    if (derived_ptr2) {
        derived_ptr2->print();  // 런타임에 타입 확인
    } else {
        std::cout << "Cast failed" << std::endl;
    }
    
    delete base_ptr;
    return 0;
}

연습 문제

  1. int, float, double 타입 간의 변환을 수행하고, 각 변환 과정에서 발생할 수 있는 정밀도 손실을 관찰하는 프로그램을 작성하세요.
  2. 부호 있는 정수와 부호 없는 정수 간의 변환을 수행하고, 오버플로우가 발생하는 경우를 찾아 결과를 출력하는 프로그램을 작성하세요.
  3. dynamic_cast를 사용하여 다형성을 가진 클래스 계층에서 안전한 타입 변환을 수행하는 예제를 작성하세요.


참고 자료