C++ Explicit Casting (C++ 명시적 캐스팅)
C의 캐스팅이 논리적이지 않고, 위험성이 있으며, 버그 가능성이 높다.
그래서 C++에서는 새로운 캐스팅 방법을 소개하고 있다.
C언어의 캐스팅 방법 :
int* p1 = (int*)malloc(sizeof(int)*10); // C언어의 캐스팅 방법 : C++에서도 사용은 가능하다.
C++의 캐스팅 방법 :
#include <iostream>
#include <cstdlib>
int main()
{
int* p1 = static_cast<int*>(malloc(sizeof(int)*10)); // C++ 에서 사용하는 캐스팅 방법
free(p1);
}
C언어 방식의 캐스팅의 단점 :
아래 두 가지 경우가 대표적인 c언어에서 발생할 수 있는 캐스팅 문제이다.
단점 예제 (1) :
#include <iostream>
int main()
{
int n = 0;
//double* p1 = &n; // error
double* p1 = (double*)&n; // ok
*p1 = 3.4;
}
>> int 형은 4byte, double 형은 8byte 이지만 각 데이타를 가리키는 포인터형 주소값은 4byte 이기 때문에 (double*)를 사용한 C언어 캐스팅으로 형변환이 가능하다.
문제는 *p1 (p1이 가리키는 곳)에 3.4 (더블형 값) 을 넣게 되면 문제가 발생하게 된다.
시스템이 오류를 내서 죽을 수도 있는데, 다른 곳의 값을 변경하게 되는 불상사가 발생할 수 있다. (예측할 수 없는 에러가 발생하게 된다.)
단점 예제 (2) :
#include <iostream>
int main()
{
const int c = 10;
//int* p2 = &c; // error
int* p2 = (int*)&c; // ok
*p2 = 20;
std::cout << c << std::endl; // 10 ? 20
}
>> const로 정의된 c 가 10 으로 정의했는데, (int *) 형변환을 통해 int* p2로 캐스팅되어 들어갈 수 있다.
*p2를 20으로 변경했다면 과연 c를 출력했을 때 무슨 값을 출력해야 하는가.
임배디드 코딩에서는 해당 캐스팅이 필요한데, 문제는 개발자 의도인지 실수인지 구별할 수가 없다는데 있다.
실행해보면 c 값으로 10이 출력된다. 오히려 실행이 되어 더 무서운 경우이다. 나중에 어떤 문제를 가져올지 모른다.
C++에서의 캐스팅은?
- C++에서는 용도별로 다른 캐스팅 방법을 사용한다.
- 용도 별로 4개의 캐스팅 연산자를 제공한다.
static_cast
- 가장 기본적인 캐스팅 연산자
- 정수와 실수 사이의 변환, 열거형과 정수 사이의 변환
- void* -> 다른 타입 *변환
- 배열 -> 포인터, 함수-> 함수 포인터 등
- 상수성을 제거하거나 서로 다른 타입의 포인터 끼리의 변환은 허용하지 않는다. (단, 상속 관계는 허용한다.)
#include <cstdlib> // malloc, free 함수 선언된 헤더
void foo(int) {}
void foo(double) {}
int main(void)
{
const int c = 10;
double d = 3.4;
int n = static_cast<int>(d); // 실수를 정수로 변환, double 을 int로 변환
int* p1 = static_cast<int*>(malloc(100)); // void* 를 다른 타입으로 변환 가능
auto p2 = static_cast<void(*)(int)>( &foo); // 함수 이름이 오버로딩 되어 있을 때,
int* p3 = static_cast<int*>(&d); // error : 서로 다른 타입의 포인터 변환은 허용하지 않는다.
int* p4 = static_cast<int*>(&c); // error : 상수성을 제거하는 캐스팅은 허용하지 않는다.
}
main.cpp:15:35: error: invalid static_cast from type ‘double*’ to type ‘int*’
main.cpp:16:35: error: invalid static_cast from type ‘const int*’ to type ‘int*’
reinterpret_cast
- 서로 다른 포인터 타입 끼리의 변환
- 정수와 포인터 사이의 변환
아래와 같이 double포인터 에 int n의 주소를 넣는 코드는 위험하며, 아래와 같이 error를 발생시킨다.
static_cast가 아닌 reinterpret_cast로 변환이 가능하다.
int main()
{
int n = 10;
double* p1 = &n; // 어떻게 캐스팅이 가능할까?
int* p2 =10; // (임배디드 코딩) 주소값을 강제로 넣고 싶은 경우!
}
위의 코드를 아래와 같이 reinterpret_cast로 가능하다. 사용에 유념해야 한다.
int main()
{
int n = 10;
double* p1 = reinterpret_cast<double*>(&n);
int* p2 = reinterpret_cast<int*>(10);
}
주의!
정수 n을 d로 변경하기 위해 reinterpret_cast를 사용하면 아래와 같은 에러가 발생한다. 위에 제시된 두 가지 용도 이외로 사용이 불가하다.
int main()
{
double d = reinterpret_cast<double>(n);
}
const_cast
포인터와 참조형의 상수성(const)과 volatilie 속성을 제거하는 데 사용
reinterpret_cast는 서로 다른 타입끼리 변환은 가능하지만 const가 붙어 있으면 안된다.
int main()
{
const int c = 10;
volatile int v = 20;
int n = c;
// const가 있는 &c를 캐스트 할 수 있는 유일한 캐스트는 const_cast뿐
int* p1 = const_cast<int*>(&c);
// volatile 있는 것 역시 const_cast로만 캐스트 가능
int* p2 = const_cast<int*>(&v);
// const_cast는 const, volatile 캐스팅 용도 이외의 다른 것은 불가하다.
double* p3 = const_cast<double*>(&c); // error
}
main.cpp:15:40: error: invalid const_cast from type ‘const int*’ to type ‘double*’
예제) const int 형 변수의 주소를 char* 변수에 담아보기
int main()
{
const int c = 10;
//char* p = static_cast<char*>(&c); // const 속성 제거 불가, int 형-> char* 불가
//char* p = const_cast<char*>(&c); // const 제거 가능, int 형-> char* 불가
//char* p = reinterpret_cast<char*>(&c); // const 속성 제거 불가, int 형-> char* 가능
// ======== 두번의 캐스팅으로 가능함! ==========
char* p1 = reinterpret_cast<char*>( // 2) int를 char* 포인터로 변경
const_cast<int*>( &c ) ); // 1) const int 속성에서 const 제거
// 위의 방법과 반대의 순서로도 가능하다. 단, const 를 달고 있는 채로 수행해야 함.
char* p2 = const_cast<char*>(
reinterpret_cast<const char*>( &c ) );
// 이 방법도 가능하나, 개발자의 의도가 명확하지 않음.
char* p3 = (char*)&c;
// c++이 c에 비해 코드가 복잡하다는 단점아닌 단점....
}
dynamic_cast
안전한 다운 캐스팅 (기반 클래스 포인터를 안전하게 파생 클래스 타입의 포인터로 캐스팅할 때 사용)
실행 시간 캐스팅 - 실행 시간 오버헤드가 존재
>> 나중에 별도 포스팅으로~!!
'C++' 카테고리의 다른 글
[C++] 객체 지향 프로그래밍 OOP (0) | 2021.08.16 |
---|---|
[C++] 동적메모리 할당 (new, delete), nullptr (0) | 2021.08.15 |
[C++] const reference, return by reference (0) | 2021.08.14 |
[C++] reference 개념 (0) | 2021.08.13 |
[C++] range-for, if init, if constexpr (0) | 2021.08.12 |
댓글