형식이 없음을 나타내는 void 활용
void test()
{
std::cout << "Test" << std::endl;
}
int test(void)
{
std::cout << "Test" << std::endl;
return 1;
}
- 어떤 변수라도 가리킬 수 있는 제네릭 포인터를 만들때 사용
int int_value;
float float_value;
void *ptr_value;
ptr_value = &int_value;
ptr_value = &float_value;
N bit 의 정수 범위
- signed : -2^(n-1) ~ 2^(n-1) -1
- unsigned : 0 ~ 2^n -1
명시적 형변환 방법
- static_cast<변환 형식>(변환 대상) : 논리적으로 변경할 수 있는 형 변환 모두 가능, 상속 관계에 있는 포인터끼리 변환도 지원(업케스팅 지원)
#include <iostream>
using namespace std;
class Base {};
class Derived : public Base {};
int main() {
// 기본형 변환
double d = 3.14;
int i = static_cast<int>(d); // 실수 → 정수
cout << i << endl; // 3
// 상속 관계 변환 (업캐스트)
Derived derived;
Base* basePtr = static_cast<Base*>(&derived); // 안전
// void* → 특정 타입
void* vp = &i;
int* ip = static_cast<int*>(vp);
cout << *ip << endl; // 3
}
- const_cast<변환 형식>(변환 대상) : 포인터 및 레퍼런스 형식에서만 사용 가능, const, volatile 제거할 때 사용
#include <iostream>
using namespace std;
void PrintValue(const int* ptr) {
// const_cast로 const 제거
int* modifiable = const_cast<int*>(ptr);
*modifiable = 20; // 위험하지만 예시용
cout << *modifiable << endl;
}
int main() {
int x = 10;
PrintValue(&x); // const 제거 가능
cout << x << endl; // 20 출력
}
- reinterpret_cast<변환 형식>(변환 대상) : 일반적인 명시적 형 변환과 동일함, const를 사용하는 변환 대상은 사용할 수 없음
#include <iostream>
using namespace std;
int main() {
int x = 0x12345678;
char* p = reinterpret_cast<char*>(&x);
// 메모리의 첫 바이트 출력 (엔디안에 따라 다름)
cout << hex << (int)(unsigned char)p[0] << endl;
// 정수 주소를 포인터로 변환
uintptr_t addr = reinterpret_cast<uintptr_t>(&x);
int* samePtr = reinterpret_cast<int*>(addr);
cout << *samePtr << endl; // 0x12345678
}
- dynamic_cast<변환 형식>(변환 대상) : 클래스의 포인터 및 레퍼런스 변수 간의 형 변환 시 사용, 안전한 다운캐스팅(down-casting)을 위해 사용
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() = default; // RTTI용
};
class Derived : public Base {
public:
void Speak() { cout << "I'm Derived" << endl; }
};
int main() {
Base* base = new Derived();
Derived* d1 = dynamic_cast<Derived*>(base); // 안전한 다운캐스트
if (d1) d1->Speak();
Base* another = new Base();
Derived* d2 = dynamic_cast<Derived*>(another); // 실패 -> nullptr
if (!d2) cout << "Cast failed" << endl;
delete base;
delete another;
}
사용자 정의 리터럴
- 리터럴을 나타내는 접미사를 함수 이름으로 만든다.
- 형식 : 반환 타임 operator"" 리터럴 접미사(매개변수)
#include <iostream>
using namespace std;
const long double km_per_mile = 1.609344L;
// _km 사용자 리터럴 정의
long double operator"" _km(long double val) {
return val; // km 리터럴: 아무 작업 없이 그대로 반환
}
// _mi 사용자 리터럴 정의
long double operator"" _mi(long double val) {
return val * km_per_mile; // mi 리터럴: mile을 km로 변환하여 반환
}
int main() {
long double distance_1 = 1.0_km; // km는 그대로 저장
long double distance_2 = 1.0_mi; // mile은 km 단위로 변환되어 저장
cout << distance_1 + distance_2 << " km" << endl; // km값으로 출력
return 0;
}
2의 보수
- 1의 보수에 1을 더하면 2의 보수를 구할 수 있다.
- 2의 보수법은 양수의 모든 비트를 반전한 1의 보수에 1을 더해, 음수를 표현하는 방법으로 활용된다.
#include <iostream>
using namespace std;
int main() {
unsigned int value = 10;
int value_a = ~value; // 1의 보수
cout << value_a << endl; // 결과 : - 11
int value_b = value_a + 1; // 2의 보수
cout << value_b << endl; // 결과 : -10
return 0;
}
비트 연산
| a |
b |
AND(&) |
OR(|) |
XOR(^) |
| 0 |
0 |
0 |
0 |
0 |
| 0 |
1 |
0 |
1 |
1 |
| 1 |
0 |
0 |
1 |
1 |
| 1 |
1 |
1 |
1 |
0 |
논리 시프트 연산, 산술 시프트 연산
| 구분 |
논리 시프트 (Logical Shift) |
산술 시프트 (Arithmetic Shift) |
| 목적 |
단순히 비트를 이동 (unsigned 용도) |
부호를 유지하면서 이동 (signed 용도) |
| 빈 자리 채움 |
항상 0으로 채움 |
왼쪽 시프트: 0, 오른쪽 시프트: 부호 비트로 채움 |
| 적용 대상 |
unsigned 정수 |
signed 정수 |
| 부호 보존 여부 |
❌ 부호 깨짐 |
✅ 부호 유지 |
#include <iostream>
#include <bitset>
using namespace std;
int main() {
unsigned char u = 0b10110010; // 178 (unsigned)
signed char s = 0b10110010; // -78 (signed, 2의 보수 표현)
cout << "Before:" << endl;
cout << "unsigned: " << bitset<8>(u) << endl;
cout << "signed: " << bitset<8>(s) << endl;
// 오른쪽 시프트 2비트
unsigned char u_shift = u >> 2;
signed char s_shift = s >> 2;
cout << "\nAfter >> 2:" << endl;
cout << "Logical (unsigned): " << bitset<8>(u_shift) << endl;
cout << "Arithmetic (signed): " << bitset<8>(s_shift) << endl;
}
/* 결과 값
Before:
unsigned: 10110010
signed: 10110010
After >> 2:
Logical (unsigned): 00101100
Arithmetic (signed): 11101100
*/