-
[Pointer] 정수형을 문자형으로개발/C·C++ 2021. 5. 28. 22:28
정수형 포인터 변수를 초기화할 때 정수형 변수의 주소값을 넣는 이유는, 메모리에서 데이터를 읽는 간격이 자료형의 크기로 결정되기 때문입니다.
int
포인터 변수p
는++p
연산을 하면 4바이트를 이동하고,short
포인터 변수s
는++s
연산을 하면 2바이트를 이동합니다. 컴파일 단계에서, 메모리 크기 단위를 포인터의 타입으로 파악할 수 있습니다. 때문에 포인터의 타입을 다른 타입으로 변환하다고 해서, 역참조하고 있는 내용이 바뀌는 건 아닙니다.아래 예제를 봅시다.
s1
에는 260,s2
에는 2를 할당했습니다. 구초제 포인터의 타입 캐스팅을 통해Family1
의 객체인f1
의 주소값을Family2
포인터 변수에 넣었습니다.f1
의short
변수들은f2
의char
배열에 할당됩니다. 260인s1
는,ch
배열의 0, 1 인덱스에 각각 4, 1의 형태로 들어갔습니다. 2바이트short
정수를 1바이트char
자료형으로 표현한 것입니다. 풀어 보면 (256^0) * 4 + 256(256^1) * 1입니다.s2
의 2는 2, 0으로 표현됩니다. 1(256^0) * 2 + 256(256^1) * 0인 것이지요. 여기에선 short와 char 사이에서 직접 포인터 타입을 변환하지 않았지만, 이를 멤버 변수로 가진 구조체 포인터의 형을 변환, 대입하여 멤버 변수의 타입이 달라도 메모리에 문제 없이 데이터가 들어간다는 것을 보여줍니다.두 번째 예제는 포인터 변수의 타입이 메모리를 어떤 간격으로 읽는지를 나타냅니다.
int
형 배열에서는 a[3]과 a[13]이 10이라는 간격을 가지지만, 이를char
포인터로 변환하면 40 간격이 됩니다.#include <iostream> using namespace std; struct Family1 { unsigned short s1; unsigned short s2; }; struct Family2 { unsigned char ch[6]; }; int main() { Family1 f1; f1.s1 = 260; f1.s2 = 2; Family2* f2 = reinterpret_cast<Family2*>(&f1); cout << static_cast<unsigned short>(f2->ch[0]) // 4 << static_cast<unsigned short>(f2->ch[1]) << endl; // 1 cout << static_cast<unsigned short>(f2->ch[2]) // 2 << static_cast<unsigned short>(f2->ch[3]) << endl; // 0 cout << endl; int a[20] = { 0 }; int* p = &a[3]; int* q = &a[13]; ptrdiff_t diff1 = q - p; // This is 10 cout << diff1 << endl; char* x = (char*)p; char* y = (char*)q; ptrdiff_t diff2 = y - x; // 40. This is 10 times sizeof(int) cout << diff2 << endl; }
윈도우에서 리스닝 소켓을 생성하고 바인드를 하기 전에 포트, 아이피 주소 등을 설정해주는데, 여기에도 위와 비슷한 과정이 있습니다.
SOCKADDR_IN addr_in; memset(&addr_in, 0, sizeof SOCKADDR_IN); addr_in.sin_family = AF_INET; addr_in.sin_port = htons(server_config_->port_); addr_in.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(listen_socket_, (sockaddr*)&addr_in, sizeof addr_in) == SOCKET_ERROR) { // do something }
bind
함수의 두 번째 인수는sockaddr*
이지만,SOCKADDR_IN
객체를 만들어 주소값을sockaddr*
로 캐스팅해서 넘깁니다. 포트랑 아이피를 각각USHORT
,ULONG
으로 넣는데, 이를 개발자가sockaddr
에 있는char
형 배열에 일일이 넣는 것은 다소 번거롭습니다. 작업하기 편하게SOCKADDR_IN
객체에 데이터를 넣어서 포인터 형 변환을 해서 전달하면 됩니다. 그러면bind
함수가 내부적으로 자료형의 크기만큼 참조하겠죠.typedef struct sockaddr_in { #if(_WIN32_WINNT < 0x0600) short sin_family; #else //(_WIN32_WINNT < 0x0600) ADDRESS_FAMILY sin_family; #endif //(_WIN32_WINNT < 0x0600) USHORT sin_port; IN_ADDR sin_addr; CHAR sin_zero[8]; } SOCKADDR_IN, *PSOCKADDR_IN; ///////////////////////////////////////////////////////////////////////////// typedef struct sockaddr { #if (_WIN32_WINNT < 0x0600) u_short sa_family; #else ADDRESS_FAMILY sa_family; // Address family. #endif //(_WIN32_WINNT < 0x0600) CHAR sa_data[14]; // Up to 14 bytes of direct address. } SOCKADDR, *PSOCKADDR, FAR *LPSOCKADDR;
>>참고 사이트
https://stackoverflow.com/questions/39854610/casting-int-pointer-to-char-pointer
'개발 > C·C++' 카테고리의 다른 글
IOCP(2) (0) 2021.06.04 [Design Pattern] Observer (0) 2021.05.30 IOCP(1) (0) 2021.05.25 [Rvalue reference] Rvalue Reference(3) (0) 2021.05.21 [Rvalue reference] Move Semantics(2) (0) 2021.05.12