반응형

이전글

https://mtding00.tistory.com/14

 

static_cast 연산자

 

static_cast 연산자

static_cast 연산자static_cast Operator 이 문서의 내용 --> 변환는 식 의 형식으로 유형-id 식에 있는 형식에만 기반 합니다.Converts an expression to the type of type-id, based only on the types that are present in the expression. 구문Syntax static_cast ( expression ) 표준 C++에서는 변환의 안전성을 보장하기 위해

docs.microsoft.com

구문

static_cast <type-id> ( expression )

 

expression(인자)가 현재의 expression 형으로만 기반해 type-id 형으로 변환됩니다.

설명

표준 C++에서는 변환의 안전성을 보장하기 위해 런타임 형식 검사가 수행되지 않습니다. C++/CX에서는 컴파일 시간 및 런타임 검사가 수행됩니다. 자세한 내용은 링크에 참고하세요.

 

static_cast 연산자는 기반 클래스 포인터를 파생 클래스 포인터로 변환하는 식으로 사용될 수 있습니다. 이러한 변환은 항상 안전한 것은 아닙니다.

 

보통 [ 열거형에서 int형 ] 또는 [ int형에서 float형으로 ] 변환하려는 경우, static_cast 연산자를 사용해 해당 데이터 관련된 변환을 명시적으로 확정지을 수 있습니다. static_cast 변환은 dynamic_cast 변환만큼 안전하지 않습니다. static_cast dynamic_cast에서 수행하는 런타임 형식 검사를 수행하지 않기 때문입니다. dynamic_cast에서는 모호한 포인터에 대해서는 포인터 변환이 실패하지만, static_cast에서는 마치 아무 문제가 없는 것처럼 처리를 하여 값을 반환합니다-> 이는 매우 위험합니다. 이렇게 dynamic_cast가 더 위험한 요소를 내포하지만, dynamic_cast는 포인터나 참조형에서만 작동을 한다는 점이 있으며, 런타임 형식 체크는 [오버헤드] 입니다.

 

오버헤드-Overhead: https://terms.naver.com/entry.nhn?docId=831832&cid=42344&categoryId=42344

더보기

컴퓨터가 사용자(user) 프로그램을 실행할 때 직접 사용자 프로그램 처리를 하지 않는 부분. 구체적으로는 운영 체제 시스템을 관리하는 데 필요로 하는 CPU 타임이나 메모리 용량을 오버헤드라고도 하는데, OS가 처리하는 시스템 자원을 유효하게 이용하여 스루풋을 향상시키기 위해서는 필요 불가결한 것이기 때문에 OS의 설계에는 어떻게 오버헤드를 최소한으로 하고 또한 스루풋을 향상시키는가가 중요하게 된다. OS를 만드는 경우, 일괄 처리(batch processing)나 다중 처리(multiprocessing) 등의 처리 형식이나 하드웨어의 능력 등에 따른 오버헤드를 고려할 필요가 있다.

[네이버 지식백과] 부담 [overhead] (컴퓨터인터넷IT용어대사전, 2011. 1. 20., 전산용어사전편찬위원회)

자세한 내용은 dynamic_cast 링크를 따라가세요.

 

다음 예제에서, D* pd2 = static_cast<D*>(pb); 줄은 클래스 [D]가 클래스 [B]에는 없는 변수나 함수를 가질 수 있기 때문에 안전하지 않습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
// compile with: /LD
class B {};
 
class D : public B {};
 
void f(B* pb, D* pd) {
   D* pd2 = static_cast<D*>(pb);   // Not safe, D can have fields
                                   // and methods that are not in B.
 
   B* pb2 = static_cast<B*>(pd);   // Safe conversion, D always
                                   // contains all of B.
}
 
 

dynamic_cast 와 비교해 보면, [pb]를 static_cast 연산 시 런타임 체크를 수행하지 않습니다.  pb가 가리키는 개체는 유형 D의 개체가 아닐 수 있으며, 이 경우 *pd2를 사용하는 것은 매우 위험합니다. 예를 들어, D 클래스가 아닌 B 클래스의 멤버인 함수를 호출하면 액세스 위반이 발생할 수 있습니다.

-> 부모 B를 자식 클래스 D로 다운캐스팅 했을 때, static_cast 연산은 그냥 이루어지고 이때 본체는 여전히 부모이기 때문에 자식 포인터 D에서 D에만 있는 함수나 변수를 호출 시 터질 수 있다는 것이다. 이는 컴파일 단계에서 잡힐 수 없다. 왜? -> 구문 상으로는 변환이 완료되어 이미 B가 D로 된 것으로 치기 때문이다.

 

 

dynamic_cast 과 static_cast 연산자는 클래스 계층 구조 전반에 걸쳐 포인터를 이동합니다. 그러나 static_cast [캐스트 문]에서 제공된 정보에만 전적으로 의존하므로, 안전하지 않을 수 있으므로 있습니다.

 

예를 들어:

1
2
3
4
5
6
7
8
9
10
11
12
// compile with: /LD /GR
class B {
public:
   virtual void Test(){}
};
class D : public B {};
 
void f(B* pb) {
   D* pd1 = dynamic_cast<D*>(pb);
   D* pd2 = static_cast<D*>(pb);
}
 
 
  • 만약 [pb] 가 [D] 형식의 개체를 가리킬 경우, [pd1]  [pd2]는 동일한 값을 얻습니다. 또한 pb == 0일 경우 같은 값을 얻습니다.
    -> 이는 전자의 경우 이미 Casting 되어있는 경우를 말하고, 후자는 말 그대로 pb 가 0값일 경우를 말한다.
  • 만약,  [pb] 포인터가 완전한 클래스 [D] 형이 아니고 클래스 [B]형이면, dynamic_cast 연산 시 0을 반환한다는 것을 알고 있어야 합니다.
    -> 이유인 즉슨, 본체가 클래스 B형이기 때문이다. dynamic_cast는 본체가 변환되는 포인터와의 일치점이 모호한 관계라면 0을 반환한다. 만약 정상적으로 dynamic_cast를 사용한 다운캐스팅을 시행하고 싶다면
  • D* pd1 = dynamic_cast<D*>(pb); 이전에  B* pb = new D; 와 같은 본체가 클래스 [D] 형식을 갖추고 있어야 한다. 이는 사실 바로 위에서 따진 경우와 일치한다.
  • 따라서 static_cast 연산이 수행하는 암시적 변환이 역변환을 수행할 수 있습니다. 이 경우에 결과값이 확실하지 않습니다. 결국, 프로그래머는 static_cast 연산 결과로 남는 메모리가 발생하는지의 여부, 변환이 안전한지부터 확인해야 합니다.
  • 이 동작은 클래스 형식 이외의 형식에도 적용됩니다. 예를 들어 static_cast 는 [정수형 int] 에서 [문자형 char]로 변환할 수 있습니다. 그러나 char 형은 결과값 int 형을 다 담지 못하는 값입니다. 즉, 다시 말하연 프로그래머는 static_cast 연산 결과로 남는 메모리가 발생하는지의 여부, 변환이 안전한지부터 확인해야 합니다.
  • static_cast 연산자는 표준 변환(기본자료형) 뿐 아니라 사용자 정의 클래스를 포함한 그 어떤 암시적 변환을 수행하는데 사용할 수 있습니다.

 

 

예를 들어:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// compile with: /LD /GR
typedef unsigned char BYTE;
 
void f() {
   char ch;
   int i = 65;
   float f = 2.5;
   double dbl;
 
   ch = static_cast<char>(i);   // int to char
   dbl = static_cast<double>(f);   // float to double
   i = static_cast<BYTE>(ch);
}
 
 
  • static_cast 은 연산자 열거형 형식(enum)을 명시적으로 정수값(integer value)으로 변환할 수 있습니다. 만약 정수 계열 형식의 값이 열거형 값 범위에 속하지 않으면, 결과값은 정의되지 않습니다.
  • static_cast 연산자는 null 포인터를 대상 형식의 null 포인터 값으로 변환합니다.
  • 모든 표현식은 static_cast 연산자에 의해 명시적으로 void 유형으로 변환될 수 있습니다. 대상 void 유형에는 선택적으로 const, volatile 또는 __unaligned 속성이 포함될 수 있습니다.
  • static_cast 연산자는 const, volatile, 또는 __unaligned 특성을 변환(Cast)할 수 없습니다. 이러한 속성을 제거하려면 const_cast 연산자를 참고하십시오.
  • C++/CLI: 재배치 가비지 수집기(Relocating Garbage Collector)이 해당 변환을 확인하지 않는 위험이 있으므로, static_cast를 올바르게 사용하려면 중요코드(perfomance-critical)에서만 사용해야합니다. 만약 릴리즈모드(release-mode)에서 static_cast를 사용하려면, 우선 디버그 빌드에서 safe_cast로 빌드 성공을 보장하십시오.
    -> 닷넷용 즉, 관리코드영역이다. 이 부분에 정말 자세한 것을 알고 싶다면 직접 링크를 들어가길 바란다. 이 글에서는 safe_cast를 다루지 않는다. (물론 차후에 해당 문구가 삭제되고 추가될 여부는 남아있다.)

참고자료

캐스팅 연산자
키워드(C++)

 

static_cast 정리

  • 사용법 - static_cast<type-id> ( expression )
  • 클래스의 상속여부, 포인터의 여부를 떠나 사용자 정의 및 자료형에도 변환 사용 가능
  • 클래스는 다운캐스팅 시 함수의 존재, 변수의 존재 여부에 따라 오류 발생 가능
  • 런타임 형식 체크를 하지 않아 dynamic_cast 비해 빠르다.
  • 자료형 변환 시 메모리가 잘리는 부분이 있는지 주의 (예: int -> char)
  • null 포인터 변환 시 type-id 형의 null 포인터로 변환

 

const_cast 연산자

 

const_cast 연산자

const_cast 연산자const_cast Operator 이 문서의 내용 --> 클래스에서 const, volatile 및 __unaligned 특성을 제거합니다.Removes the const, volatile, and __unaligned attribute(s) from a class. 구문Syntax const_cast (expression) 모든 개체 형식에 대한 포인터 또는 데이터 멤버에 대한 포인터는 const, volatile 및 __un

docs.microsoft.com

클래스에서 const, volatile  __unaligned 특성을 제거합니다.

구문

const_cast <type-id> (expression)

설명

모든 개체 형식에 대한 포인터 또는 데이터 멤버에 대한 포인터는 const, volatile  __unaligned 한정자를 제외하고 동일한 형식으로 명시적으로 변환될 수 있습니다. 포인터 및 참조의 경우 결과는 원래 개체를 참조합니다. 데이터 멤버에 대한 포인터의 경우 결과는 데이터 멤버에 대한 원래(캐스팅 해제) 포인터와 동일한 멤버를 참조합니다. 참조 개체의 형식에 따라 결과 포인터, 참조 또는 데이터 멤버에 대한 포인터를 통한 쓰기 작업으로 인해 정의되지 않은 동작이 발생할 수 있습니다.

 

  • const_cast 연산자를 사용하여 상수 변수의 상수 상태를 직접 재정의할 수 없습니다.
  • const_cast 연산자는 null 포인터 값을 대상 형식의 null 포인터 값으로 변환합니다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// compile with: /EHsc
#include <iostream>
 
using namespace std;
class CCTest {
public:
   void setNumber( int );
   void printNumber() const;
private:
   int number;
};
 
void CCTest::setNumber( int num ) { number = num; }
 
void CCTest::printNumber() const {
   cout << "\nBefore: " << number;
   const_cast< CCTest * >this )->number--;
   cout << "\nAfter: " << number;
}
 
int main() {
   CCTest X;
   X.setNumber( 8 );
   X.printNumber();
}
 
 

 

const_cast를 포함하는 줄(18)에서 this 포인터의 데이터 형식은 const CCTest *입니다. const_cast 연산자는 this 포인터의 데이터 형식을 CCTest *로 변경하므로 number 멤버가 수정될 수 있습니다. 캐스팅은 그것이 표시되는 문의 나머지 부분에서만 지속됩니다.

-> 변수 선언이 const로 되어있는 것이 아니라 함수가 const로 정의되어 있다 +.+

참고 항목

캐스팅 연산자
키워드(C++)

 

 

 

 

reinterpret_cast 연산자

 

reinterpret_cast 연산자

reinterpret_cast 연산자reinterpret_cast Operator 이 문서의 내용 --> 포인터가 다른 포인터 형식으로 변환될 수 있도록 합니다.Allows any pointer to be converted into any other pointer type. 또한 정수 계열 형식이 포인터 형식으로 변환될 수 있도록 하고 그 반대로도 변환될 수 있도록 합니다.Also allows any integral type to be converted

docs.microsoft.com

포인터가 다른 포인터 형식으로 변환될 수 있도록 합니다. 또한 정수 계열 형식이 포인터 형식으로 변환될 수 있도록 하고 그 반대로도 변환될 수 있도록 합니다.

구문

reinterpret_cast < type-id > ( expression )

설명

  • reinterpret_cast 연산자의 잘못된 사용은 쉽게 안전한 코드가 되지 않을 수 있습니다. 원하는 변환이 본질적으로 낮은 수준이 아니라면(간단한 변환이 아니라면), 다른 캐스트 연산자 중 하나를 사용해야 합니다.
  • reinterpret_cast 연산자는 [char* 형]에서 [int* 형]으로 또는, [One_class*]에서 [Unrelated_class]과 같은 변환에 사용되는 경우 본질적으로 안전하지 않은 경우입니다.
  • reinterpret_cast 의 결과값은 원래 형식으로 다시 캐스팅 되는 경우 이외의 용도로는 안전하게 사용할 수 없습니다. 다른 용도로는 변환되지 않는 경우가 많습니다.
  • reinterpret_cast 연산자는 const, volatile, 또는 __unaligned 특성을 변환(Cast)할 수 없습니다. 이러한 속성을 제거하려면 const_cast 연산자를 참고하십시오.
  • reinterpret_cast 연산자는 대상 형식의 null 포인터 값으로 null 포인터 값을 변환합니다.
  • reinterpret_cast의 한 가지 실제적인 사용법은 해시 함수 (hash function)에 있습니다. 이 함수는 값을 인덱스에 매핑하여 두 개의 별개 값이 거의 같은 인덱스로 끝나는 방식으로 매핑합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
using namespace std;
 
// Returns a hash code based on an address
unsigned short Hash( void *p ) {
   unsigned int val = reinterpret_cast<unsigned int>( p );
   return ( unsigned short )( val ^ (val >> 16));
}
 
using namespace std;
int main() {
   int a[20];
   for ( int i = 0; i < 20; i++ )
      cout << Hash( a + i ) << endl;
}
 
 
Output:
64641
64645
64889
64893
64881
64885
64873
64877
64865
64869
64857
64861
64849
64853
64841
64845
64833
64837
64825
64829
 
 

reinterpret_cast를 사용하면 포인터를 정수 유형으로 처리할 수 ​​있습니다. 그 결과는 비트 시프트 연산이 되고 자체적으로 XOR연산(배타적 논리합)을 하여 고유색인(높은 확률의 고유한 색인)을 생성합니다. 인덱스는 표준 C 스타일 캐스트에 의해 함수의 리턴 유형으로 잘립니다.

-> 이 예제는 포인터 값을 변환(cast)을 통해 short 정수형으로 바꾸는데에 초점을 맞추고 있다. 예제 실행 결과 예상과 같이 Output의 값은 실행마다 바뀌는 것을 확인할 수 있었다.

참고자료

캐스팅 연산자
키워드(C++)

반응형
Posted by Kestone Black Box
,