C++ Primer 1 ~ 5장 후기

2026. 4. 9. 02:09카테고리 없음

우선 C++ Primer 1~5장은 기본적인 내용이었다 

그래서 그냥 읽어 보고 기초 지식을 점검해보았다 그리고 직접 실습을 해보았다 

기본적인 개념들은 그냥 읽어보고 실습은 총3가지를 해보았다 

#include <iostream>
using namespace std;

int main() {
    char c_arr[3] = {'A', 'B', 'C'};
    int i_arr[3] = {10, 20, 30};
    double d_arr[3] = {1.1, 2.2, 3.3};

    
    cout << "char step  : " << (long long)(c_arr + 1) - (long long)c_arr << " byte" << endl;
    cout << "int step   : " << (long long)(i_arr + 1) - (long long)i_arr << " bytes" << endl;
    cout << "double step: " << (long long)(d_arr + 1) - (long long)d_arr << " bytes" << endl;

    return 0;
}

이렇게 배열은 타입마다 메모리를 건너뛰어 메모리에 할당하는것을 보았다 

char 배열
int 배열
double 배열은 8칸씩

 

그리고 각 Cast들에 대해 조금 확인을 해보았다 

1. static_cast

컴파일 타임에 변환 (가장 기본)

특징

  • 타입 간 명시적 변환
  • 컴파일러가 안전하다고 판단하면 허용
int main() {
    double d = 3.14;
    
    int i = static_cast<int>(d);

    std::cout << "double d의 주소: " << &d << " | 값: " << d << std::endl;
    std::cout << "int i의 주소   : " << &i << " | 값: " << i << std::endl;

 
    return 0;
}

double d의 메모리
int i 의 메모리
어셈블리

 -> "static_cast<int>(double)를 실행하면 CPU 레벨에서 cvttsd2si 명령어가 실행되는 것을 확인했다. 이는 단순히 메모리를 다르게 보는 것이 아니라, 실제로 소수점을 잘라내고 정수 비트로 재구성하는 물리적인 변환 과정이 일어난다는 것을 의미한다."

2. dynamic_cast

런타임 타입 체크 (RTTI 기반)

특징

  • 상속 관계에서만 사용 가능
  • 반드시 virtual 함수가 있는 클래스 필요
  • 실패 시:
    • 포인터 → nullptr
    • 참조 → 예외 발생
#include <iostream>

class Base {
public:
    virtual void hello() { std::cout << "Base\n"; } 
};

class Derived : public Base {
public:
    void hello() override { std::cout << "Derived\n"; }
};

int main() {
    Base* b = new Derived(); 

    
    Derived* d = dynamic_cast<Derived*>(b); 

    if (d) d->hello();

    delete b;
    return 0;
}

이렇게 가상함수가 있는 클래스는 반드시 VTable의 주소를가진다

 

어셈블리에서 __RTDynamicCast 이것을 호출한다 

내부 동작

  • 객체 내부의 vtable → RTTI 정보 확인
  • 실제 객체 타입을 검사해서 맞으면 변환

여기서 Dynamic Cast는 Static과 다르게 변환이 실패하면  nullptr 혹은  std::bad_cast 예외를 발생하여서 안정성에서 훨씬 좋다 (Static은 쓰레기 주소를 줘버림) 


3. const_cast

const제거

특징

  • const 속성만 변경

사용 예

 
const int a = 10;
int* p = const_cast<int*>(&a);
*p = 20;
 

내부 동작

  • 단순히 상수성만  제거
  • 실제 메모리 보호는 없음

4. reinterpret_cast

비트 단위 재해석 (가장 위험)

특징

  • 완전히 다른 타입으로 해석
  • 컴파일러는 거의 검사 안 함

사용 예

#include <iostream>

int main() {
 
    int n = 0x41424344; 

    char* p = reinterpret_cast<char*>(&n);

    std::cout << "--- reinterpret_cast 실습 ---" << std::endl;
    std::cout << "int n의 주소: " << &n << std::endl;
    std::cout << "ptr p의 주소: " << (void*)p << std::endl;

    std::cout << "p가 가리키는 첫 번째 칸의 문자: " << *p << std::endl;
    std::cout << "p가 가리키는 두 번째 칸의 문자: " << *(p + 1) << std::endl; 

    return 0;
}

어셈블리에서도 어떠한 호출이 없다 단지 Char로
주소도 똑같고
해당 메모리의 비트또한 변환이 없다

내부 동작

  • 비트 그대로 유지
  • 타입만 바꿔서 해석