갓똥
나는야 프로그래머
갓똥
전체 방문자
오늘
어제
  • 분류 전체보기 (186)
    • 프로그래밍 (146)
      • 자바 (9)
      • 안드로이드 (2)
      • 유니티 (20)
      • C++ (38)
      • C# (56)
      • HTML (2)
      • 파이썬 (3)
      • 자료구조 (2)
      • 알고리즘 (0)
      • 문제풀이 (4)
      • 디자인 패턴 (7)
      • 카카오톡 봇 (1)
      • 엑셀 (1)
      • 기타 (1)
    • 게임 (21)
      • 테일즈위버 (0)
      • 카이로소프트 (1)
      • 순위 (19)
      • 기타 (1)
    • 일상 (13)
      • 카페 (1)
      • 방탈출 (12)
    • 기타 (6)
      • 웃긴자료 (5)

블로그 메뉴

  • 홈
  • 방명록

공지사항

인기 글

태그

  • 유니티 그래프 그리기
  • c# delegate
  • C# boxing
  • Unity Graph
  • 전세계 게임 매출
  • 게임 매출 순위
  • 2020년 게임 매출
  • c# unboxing
  • 게임매출순위
  • c# Thread
  • C++ 상속
  • 유니티 골드그래프
  • pc게임 순위
  • c# collection
  • C++ 소멸자
  • 롤 골드그래프
  • C++ virtual
  • pc 게임 순위
  • C# 예외 처리
  • 글로벌게임매출
  • 강남 방탈출
  • c# 코루틴
  • 전세계게임매출순위
  • 게임 디자인 패턴
  • 알고리즘
  • 자바
  • C++
  • c# coroutine
  • 모바일 게임 순위
  • 유니티 그래프

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
갓똥

나는야 프로그래머

[C++] Explicit Casting
프로그래밍/C++

[C++] Explicit Casting

2019. 10. 25. 00:55
728x90
반응형

1. C++ Explicit Casting 개념

#include <iostream>
#include <cstdlib>

int main() {
    int* p1 = malloc(sizeof(int)*10);
    
    free(p1);
}

  - 위의 코드를 살펴보면 malloc을 사용해 메모리를 할당하고 주소를 int포인터로 받았다.

  - 하지만 사실 malloc이 반환하는 데이터 타입은 void포인터이다. 이것을 int포인터에 담을 수 있는가?

C언어와 C++언어의 문법의 차이점

  - 위의 표에 따라 C++에서는 암시적 변환이 허용되지 않아 컴파일 시 에러가 난다.

C언어와 C++언어의 캐스팅 방법

  - 그렇다면 왜 새로운 캐스팅이 필요할까?

    => C의 캐스팅은 논리적이지 않고, 위험하고, 버그의 가능성이 높다.

 


2. C언어 방식 캐스팅의 단점

#include <iostream>

int main() {
    int n = 0;
    
    //double* p1 = &n;        // error
    double* p1 = (double*)&n; // ok
    *p1 = 3.4; // ?
}

  - int타입의 주소를 double타입 포인터 변수 p1에 담고있다. 따라서 컴파일 시 에러가 난다.

  - 하지만, 강제로 double포인터로 캐스팅을 하면 문제없이 컴파일이 된다.

  - 이 때, *p1에 3.4를 넣으면 어떻게 될까?

  - 위 그림은 *p1에 3.4를 넣기 전까지의 코드를 그림으로 표현한 것이다. 여기서 *p1에 3.4를 넣는다면

  - 컴파일러가 봤을 땐 *p1이 double을 가리키므로 3.4를 넣는데 문제가 없다고 생각하고, 메모리를 8byte를 잡게 된다.

  - 이럴경우 잘못된 메모리 참조로 프로그램이 죽을 수도 있고, 더 넓게 잡힌 공간에 다른 변수가 있다면 전혀 다른 결과가 나올 수 있다.

 

#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?
}

  - 상수 int 타입 c를 10으로 선언 및 초기화 한다.

  - 이 c의 주소를 int포인터 p2에 담으면 p2의 값이 바뀔 수 있어 위험하다. 다행히 이 코드는 컴파일 시 에러가 난다.

  - 하지만 캐스팅을 통한 컴파일 오류를 없앨 수 있다. 위에서 c의 값은 10이 나올까? 20이 나올까?

 

결론

  1. 논리적으로 위험한 캐스팅도 아무런 경고 없이 허용한다.

    => 개발자의 의도인지 실수인지를 명확하게 구별할 수 없다.

  2. C++언어의 해결책

    => 용도 별로 다른 캐스팅 방법을 사용하자.

    => 용도 별로 4개의 캐스팅 연산자가 제공된다.

 


3. C++의 4개의 캐스팅 연산자

void move(int)    {}
void move(double) {}

int main(void) {
    const int c = 10;
    double d = 3.4;
    
    int  n  = static_cast<int>(d);
    int* p1 = static_cast<int*>(malloc(100));
    
    // auto p2 = &move; // error
    auto p2 = static_cast<void(*)(int)>( &move ); // ok
    
    int* p3 = static_cast<int*>(&d); // error - 포인터끼리의 변환
    int* p4 = static_cast<int*>(&c); // error - 상수성 제거
}

  - 사용 방법 : cast연산<타입>(표현식);  ->  ex. static_cast<double>(num);

 

3.1 여러가지 cast

int main() {
    int n = 10;
    
    // double* p1 = &n;
    double* p1 = reinterpret_cast<double*>(&n);
    
    // int* p2 = 10;
    int* p2 = reinterpret_cast<int*>(10);
    
    // double d = reinterpret_cast<double>(n); - error
}

  - reinterpret_cast

    => 서로 다른 타입의 포인터 사이의 변환

    => 정수와 포인터 사이의 변환

 

int main() {
    const    int c = 10;
    volatile int v = 20;
    
    int n = c;
    
    // int* p1 = &c;
    int* p1 = const_cast<int*>(&c);
    // int* p2 = &v;
    int* p2 = const_cast<int*>(&v);
    
    // double* p3 = const_cast<double*>(&c); - error
}

  - const_cast

    => 포인터 변수와 참조 변수 사이의 상수성(const)과 volatile속성을 제거하기 위한 캐스팅

 

 

  - 예제 : const int형 변수의 주소를 char*변수에 담아보기

int main() {
    cont int c = 10;
    
    // char* p = static_cast<char*>(&c);
    
    // char* p = const_cast<char*>(&c);
    
    // char* p = reinterpret_cast<char*>(&c);
    
    char* p = static_cast<char*>(
                     const_cast<int*>(&c)); // 방법1
                     
    char* p = const_cast<char*>(
                reinterpret_cast<const char*>(&c)); // 방법2
}

    => static_cast : 상수성을 제거할 수 없고 int를 char*로 바꿀수도 없다. 

    => const_cast : 상수성을 제거할 수 있으나 int를 char*로 바꿀순 없다.

    => reinterpret_cast : int를 char*로 바꿀순 있으나 상수성을 제거할 수 없다.

    => const_cast와 reinterpret_cast를 같이 사용한다.

    => 방법1. 상수성을 먼저 제거한 후 타입 변환

    => 방법2. 타입을 먼저 변환(상수성 유지) 후 상수성 제거

    => 방법3. char* p3 = (char*)&c;   -> 개발자의 의도가 명확하지 않다.

728x90
반응형

'프로그래밍 > C++' 카테고리의 다른 글

[C++] 객체지향 프로그래밍의 개념(1)  (0) 2019.10.29
[C++] 동적 메모리 할당, nullptr  (0) 2019.10.27
[C++] 레퍼런스(reference)  (0) 2019.10.22
[C++] range for / if init / if constexpr  (0) 2019.10.18
[C++] C언어와 다른 C++ 함수(2)  (0) 2019.10.11
    '프로그래밍/C++' 카테고리의 다른 글
    • [C++] 객체지향 프로그래밍의 개념(1)
    • [C++] 동적 메모리 할당, nullptr
    • [C++] 레퍼런스(reference)
    • [C++] range for / if init / if constexpr
    갓똥
    갓똥
    공부하며 알아가는 내용을 정리해 봅니다.

    티스토리툴바