본문 바로가기

Study/C,C++

[C/C++]형변환(Cast)의 종류와 사용법

형변환(Cast)는 변수의 타입을 명시적으로 변환하기 위해 사용된다. 물론 이러한 명시적인 변환 말고도 암묵적으로 컴파일러가 자동으로 변환을 해주는 암시적 형변환도 있다.

 

우선 C에서 사용하는 형변환은 다음과 같다.

int num1 = 10;
int num2 = 4;
float avg = 0.0f;
avg = (float)num1 / num2; // 명시적 형변환

num1 / num2 는 10 / 4이므로 답은 2.5가 나와야 한다. 하지만 num1과 num2는 소수점을 가지고 있지 않는 정수형 타입이기 때문에 num1/num2 자체를 정수형으로 인식하여 소수점은 버려지게 된다. 이를 막기 위해 num1을 float타입으로 명시적 형변환을 일으켜준 것이다.

 

이러한 C스타일의 Cast는 두 가지 단점이 있다. 이는 MEC++ 2장에서 참고했다.

- C 스타일의 캐스트는 형변환에 있어 그냥 무작정 변환해 버린다.

- (type-id)(e-pression) 형태의 사용법이 코드의 가독성을 해친다.

 

C스타일의 캐스팅은 아무런 제약이 없기 때문에 무작정 형변환을 했다가는 의도치 않은 결과로 고통받을 수 있다.

따라서 이런 문제들을 개선한 C++의 캐스팅 방식이 권장된다.


C++ 스타일 Casting

1. const_cast <T> (표현식)

    -const_cast는 표현식의 상수성(const)을 부여하거나 없애는 데 사용된다. (다른 Cast연산자처럼 상수성을 제외한 다른 형변환은 혀용 하지 않는다.)

char str[] = "Test";
const char* ptr = str;
std::cout << "before : " << str << endl; // 출력==> before : Test

//ptr[0] = 't'; ==>Error
char* c = const_cast<char*>(ptr); //상수성 임시 제거
c[0] = 't';
std::cout << "after : " << str << endl;// 출력==> after : test

----------------------------------------------------------------------------------------------------

int tmp = 15;
const int& ref = tmp;
cout << "before : " << tmp << endl;// 출력==> before : 15

// ref = 20; == > error;

int& r = const_cast<int&>(ref);//상수성 임시 제거
r = 30;
cout << "after : " << tmp << endl;// 출력==> after : 30

2. dynamic_cast <T> (표현식)

    -안전한 다운 캐스팅 - 주어진 객체가 어떤 클래스 상속 계통에 속한 특정 타입인지 판별해서 캐스팅. (업 캐스팅에도 사용 가능)

    -런타임 시간에 실제 해당 타입이 다운 캐스팅이 가능한지 검사하기 때문에, 런타임 비용이 조금 높은 캐스트 연산자.

class B { };
class C : public B { };
class D : public C { };

void f(D* pd) {
   C* pc = dynamic_cast<C*>(pd);   // 성공: C는 직접 기본 클래스 입니다.
                                   // pc는 pd의 C 서브오브젝트를 가리킨다.
   B* pb = dynamic_cast<B*>(pd);   // 성공: B는 간접 기본 클래스 입니다.
                                   // pb는 pd의 B 서브오브젝트를 가리킨다.
}

3. reinterpret_cast <T> (표현식)

    -Low 레벨의 캐스팅이다. 

    -임의의 포인터 타입끼리 변환을 허용한다. (정수형을 포인터로 변환 가능)

    -잘못 셔요 할 경우 결과 값이 컴파일러에 따라 다르거나, 예상하지 못한 값이 나올 수 있다.

// 주소를 정수값으로 변환하여 반환하는 함수
unsigned short Hash( void *p ) {
   unsigned int val = reinterpret_cast<unsigned int>( p );
   return ( unsigned short )( val ^ (val >> 16));
}

int main() {
   int a[20];
   for ( int i = 0; i < 20; i++ )
      std::cout << Hash( a + i ) << std::endl;
}

출력:
64641
64645
64889
64893
64881
64885
64873
64877
64865
64869
64857
64861
64849
64853
64841
64845
64833
64837
64825
64829

4. static_cast <T> (표현식)

    -암시적인 형변환을 수행하게 하는 용도.

    -dynamic_cast와는 다르게 런타임에 검사하지 않고 컴파일 타임에 검사를 진행한다.

    -포인터 타입을 다른 타입으로 변환하는 것을 허용하지 않는다. (다만, 상속 관계의 경우 허용한다.)

    -downcast시에는 unsafe 하게 동작할 수 있다. (safe 하게 변환하려면 dynamic_cast사용)

class B {};

class D : public B {};

void f(B* pb, D* pd) {
   D* pd2 = static_cast<D*>(pb);   // 안전하지 않은 변환, D가 B에게는 없는 
                                   // 필드나 메서드를 가지고 있을 수 있다.

   B* pb2 = static_cast<B*>(pd);   // 안전한 변환, D는 항상 
                                   // B의 모든걸 포함한다.
}

 

 

 

'Study > C,C++' 카테고리의 다른 글

위치에 따른 "const"의 의미들  (0) 2022.11.09