형변환 (Type Conversions)
어떤 데이터 타입이 다른 데이터 타입으로 변환되는 작업을 형변환이라고 하며,
누가 의도했는지에 따라 암묵적, 명시적 형변환으로 분류된다.
형변환의 종류
- 암묵적 변환 (컴파일러가 형변환을 의도함.)
- 명시적 변환 (프로그래머가 형변환을 의도함.)
암묵적 변환 (Implicit Conversions)
T1 형식의 데이터를 T2 형식의 변수에 대입하려고 하는 경우,
컴파일러는 두 자료형 사이의 변환연산를 찾고, 프로그래머의 지시 없이 형변환을 진행한다.
Example :
int a = 3; double b = a;
프로그래머가 의도적으로 형변환 연산자를 사용하지 않았지만,
컴파일러는 암묵적으로 int를 double로 변환하는 연산을 찾고 형변환을 진행한다.
만약, 컴파일러가 올바른 변환연산을 찾지 못했다면,
컴파일러는 형변환을 진행할 수 없다는 오류를 발생시킨다.
명시적 형변환 (Implicit Conversion)
Example :
int a = 3;
double b = (int) a; // C-style Casting.
문맥적 변환 (Contextual Conversions)
문맥에 따라 컴파일러가 진행하는 암묵적 변환.
아래와 같은 상황을 예로 들 수 있다.
- if(expr)에서 expr은 bool로 형변환됨.
- switch(expr)에서 expr은 int로 형변환됨.
- ...
표준 변환 (Standard Conversions)
- 정수 확장 (Integral Promotions)
- 정수 변환 (Integral Conversions)
- 부동소수 변환 (Floating-Point Conversions)
- 부동소수-정수 변환 (Floating-Point and Integer Conversions)
- 수학적 변환 (Arithmetic Conversions)
- 포인터 변환 (Pointer Conversions)
- 정수형 상수-포인터 변환
- ...
- char, short int
- int bit fields
- Enumerators
short a = 3;
int b = a;
- Signed to unsigned.
- Unsigned to signed.
int a = -1; unsigned int b = a;
- float to (double, long double)
- (double, long) double to float
double a = 0.3f;
float b = 0.3lf;
4. 부동소수-정수 변환 (Conversions between Integral and Floating-Point types)
정수가 부동소수로 변환될 때는, 정확하지 않은 부동소수로 변환되며, 원래 값보다 클수도 작을수도 있다.
부동소수가 정수로 변환될 때는, 소수점이 절삭된다.
int a = 3; double b = a; // b == (3.0+delta OR 3.0-delta) double x = 2.9; int y = x; // y == 2
5. 수학적 변환 (Arithmetic Conversions)
수학적인 계산 도중에 발생하고, 작은 자료형을 넓은 범위의 자료형으로 변환한다.
아래의 매커니즘을 순서대로 진행한다.
- 다른 수학적 타입(정수, 부동소수)을 만나면, 부동소수로 통일한다.
- 같은 수학적 타입(정수, 부동소수)을 만나면, 범위가 큰쪽으로 통일한다.
- 같은 수학적 타입이지만 부호형식이 다른 경우, unsigned 타입으로 통일한다.
double dVal;
float fVal;
int iVal;
unsigned long ulVal;
int main() {
// iVal converted to unsigned long
// result of multiplication converted to double
dVal = iVal * ulVal;
// ulVal converted to float
// result of addition converted to double
dVal = ulVal + fVal;
}
6. 포인터 변환 (Pointer Conversions)
포인터 변환은 아래의 상황을 가르킨다.
- 포인터를 객체로, (Pointer to Classes) // 접근 지시자와 다형성에 영향을 받는다.
- 포인터를 함수로, (Pointer to Function) // 함수 포인터
- 포인터를 보이드 타입으로, (Pointer to void)
추가적으로, 모든 포인터 타입은 void*로 변환될 수 있고,
void*는 모든 포인터 타입으로 변환될 수 있다.
이 때문에 void*는 범용 포인터 자료형(generic pointer type)이라고 불리기도 하는데,
템플릿이 없는 C-API는 void*를 인자로 받고, 다른 자료형으로 변환한다.
double a = 3.14; char* b = (char*)(void*)&a; // Compile Success. but, Runtime Error occur.
7. 정수형 상수-포인터 변환 (Integral constant-Pointer Conversions)
상수 0은 null pointer와 동일하다. (C++11 부터는 nullptr을 이용하자.)
int* i_ptr = 0; int* i_ptr = nullptr; // since c++11. nullptr != 0(NULL Pointer)
사용자 정의 형변환 (User-Defined Type Conversions)
명시적 형변환시, 표준 변환에서 일치하는 변환연산을 찾지 못했다면.
사용자가 정의한 형변환 연산이 있는지 검사한다.
Example :
class Integer{
public:
int data = 0;
explicit Integer(int _data):data{_data}{};
// User-Defined Type Conversions.
// Integer to int.
explicit operator int() const {return data;}
};
int main() {
int a = (int)Integer(3); // 3
return 0;
}
C++ 캐스팅 연산자
C++은 다음의 캐스팅 연산자를 지원한다.
- static_cast<T>
- dynamic_cast<T>
- reinterpret_cast<T>
- const_cast<T>
static_cast<T>
C-style의 캐스팅과 동일한 역할을 한다.
컴파일 타임에 형변환을 검사하고, 일치하는 변환연산을 진행한다.
런타임에는 검사하지 않는다.
dynamic_cast<T>
다형성을 이루는 클래스의 포인터에만 적용되는 캐스팅 연산자.
다형성을 거스르는 변환을 진행하면 nullptr을 반환한다.
런타임에 검사하며, 컴파일 타임에 검사하지 않는다.
reinterprete_cast<T>
비트열은 건들지 않고, 타입 자체만 바꾸는 캐스팅 연산자.
타입 자체만 바꾸기 때문에, 컴파일 에러는 발생시키지 않는다.
단, 올바르지 않은 자료형으로 바꾸고 사용한 경우 런타임에러가 발생한다.
const_cast<T>
const, volatile과 같은 제한자를 붙이거나 뗄 수 있는 캐스팅 연산자.
참고문헌
'# Lang > C++' 카테고리의 다른 글
3.2 기억영역 클래스 지정자 (0) | 2019.04.06 |
---|---|
3.1 CV 제한자 (const, volatile) (0) | 2019.03.31 |
2.2 자료형과 데이터 해석 (0) | 2019.03.27 |
2.1 자료형 (0) | 2019.03.26 |
1.3 변수와 메모리 모델 (0) | 2019.03.23 |