C++ 초급 - 2. 기본 문법 (6 - 형 변환 (Type Conversion))

2025. 2. 12. 12:08프로그래밍 언어/C++

2.6 형 변환 (Type Conversion)

C++에서 형 변환(Type Conversion)한 데이터 타입을 다른 데이터 타입으로 변환하는 과정이다.
형 변환에는 묵시적 변환(Implicit Conversion)명시적 변환(Explicit Conversion) 두 가지 방식이 있다.


(1) 묵시적 변환 (Implicit Conversion)

묵시적 변환은 컴파일러가 자동으로 수행하는 형 변환이다.
주로 작은 크기의 데이터 타입이 더 큰 크기의 데이터 타입으로 변환될 때 발생한다.

📌 자동 변환 규칙

C++에서는 다음과 같은 순서로 자동 변환이 발생한다.

char → int → float → double

즉, 더 큰 범위를 가지는 데이터 타입으로 변환되며, 데이터 손실이 발생하지 않는다.

📌 묵시적 변환 예제

#include <iostream>

int main() {
    int num = 10;
    double d = num;  // int → double 자동 변환

    std::cout << "정수 num: " << num << std::endl;
    std::cout << "자동 변환된 실수 d: " << d << std::endl;  // 10.0 출력

    return 0;
}

🔹 출력 결과

정수 num: 10
자동 변환된 실수 d: 10

💡 설명

  • int 타입의 num이 double 타입의 d로 변환됨.
  • num 값이 10에서 10.0으로 변환되었지만, 데이터 손실은 없음.

📌 묵시적 변환 예제 (다양한 타입)

#include <iostream>

int main() {
    char letter = 'A';  // 'A'는 ASCII 값 65
    int num = letter;   // char → int 자동 변환
    float f = num;      // int → float 자동 변환
    double d = f;       // float → double 자동 변환

    std::cout << "char to int: " << num << std::endl;   // 65 출력
    std::cout << "int to float: " << f << std::endl;   // 65.0 출력
    std::cout << "float to double: " << d << std::endl; // 65.0 출력

    return 0;
}

🔹 출력 결과

char to int: 65
int to float: 65
float to double: 65

💡 설명

  • 'A'가 ASCII 코드 65로 변환됨 (char → int).
  • int가 float로 변환될 때 소수점이 추가됨.
  • float가 double로 변환될 때 데이터 손실 없이 변환됨.

(2) 명시적 변환 (Explicit Conversion)

명시적 변환은 프로그래머가 직접 타입 변환을 지정하는 방법이다.
이를 통해 데이터 손실을 방지하거나, 정확한 변환을 강제할 수 있다.

명시적 변환에는 다음과 같은 방식이 있다.

  1. C 스타일 변환 (타입)변수명
  2. C++ 스타일 변환 (static_cast<T>(변수명))

📌 C 스타일 변환 (비추천)

double pi = 3.14159;
int intPi = (int)pi;  // 소수점 제거

std::cout << intPi;  // 출력: 3
  • 단점: 가독성이 떨어지고, reinterpret_cast와 같은 위험한 변환도 허용됨.

📌 C++ 스타일 변환 (static_cast)

#include <iostream>

int main() {
    double pi = 3.14159;
    int intPi = static_cast<int>(pi);  // 소수점 제거

    std::cout << "변환된 값: " << intPi << std::endl; // 출력: 3

    return 0;
}

🔹 출력 결과

변환된 값: 3

💡 static_cast<T>(변수명)을 사용하는 이유

  • C 스타일 변환보다 안전하고 명확함.
  • 불필요한 변환을 방지할 수 있음.
  • 컴파일러가 오류를 감지할 수 있음.

📌 static_cast 활용 예제

1. 정수 → 실수 변환

#include <iostream>

int main() {
    int a = 7, b = 2;
    
    double result = static_cast<double>(a) / b; // 정수 나눗셈을 실수 나눗셈으로 변환
    std::cout << "7 / 2 = " << result << std::endl;

    return 0;
}

🔹 출력 결과

7 / 2 = 3.5

💡 static_cast<double>(a)를 사용하지 않으면 7 / 2 = 3으로 출력됨.


2. 포인터 변환 (안전한 변환)

#include <iostream>

int main() {
    int num = 10;
    void* ptr = &num;  // void 포인터로 변환

    // static_cast를 사용하여 다시 int*로 변환
    int* intPtr = static_cast<int*>(ptr);
    std::cout << "포인터 변환된 값: " << *intPtr << std::endl;

    return 0;
}

🔹 출력 결과

포인터 변환된 값: 10

💡 설명

  • void*는 어떤 타입이든 가리킬 수 있는 범용 포인터.
  • static_cast<int*>를 사용하여 원래 타입으로 변환.

📌 static_cast vs reinterpret_cast 차이점

  • static_cast<T>(): 안전한 변환 (타입 변환 가능 여부를 컴파일러가 검사)
  • reinterpret_cast<T>(): 메모리 해석 방식 자체를 변경 (위험할 수 있음)
int num = 42;
double* ptr = reinterpret_cast<double*>(&num);  // 매우 위험한 변환
std::cout << *ptr;  // 예상치 못한 결과 발생 가능

⚠️ reinterpret_cast는 메모리 해석 방식을 변경하기 때문에, 주의해서 사용해야 한다.


📌 static_cast vs dynamic_cast

변환 방식 설명  사용 예제
static_cast 컴파일 시 타입 변환 static_cast<int>(3.14)
dynamic_cast 런타임 타입 변환 (다형성) dynamic_cast<Derived*>(basePtr)

💡 dynamic_cast는 상속 관계에서 런타임 타입 변환을 수행할 때 사용되며, static_cast보다 비용이 크다.


정리

형 변환 종류 설명  예제
묵시적 변환 (Implicit) 작은 타입 → 큰 타입 자동 변환 int → double
C 스타일 변환 (타입)변수 C 방식 변환 (비추천) (int)pi
static_cast<T>() 안전하고 명확한 변환 (추천) static_cast<int>(3.14)
reinterpret_cast<T>() 메모리 주소 변환 (위험) reinterpret_cast<int*>(ptr)
dynamic_cast<T>() 다형성 타입 변환 (런타임) dynamic_cast<Derived*>(basePtr)