1. 문제 확인 및 테스트
아래와 같은 코드가 있다고 하자.
#include <iostream>
int main()
{
char A[100];
char *ptr;
ptr = A;
std::cout << ptr << std::endl;
ptr = &A[0];
std::cout << ptr << std::endl;
ptr = &A[1];
std::cout << ptr << std::endl;
return (0);
}
C++
복사
기존에 알던대로, & 연산자를 이용하여 주소를 취득해 ptr에 할당하고 출력해보면 정상적으로 주소 값이 출력되어야 할 것이다.
하지만 배열의 시작점을 참조하도록 A라는 이름을 할당한 경우, A의 0번째를 참조하여 할당한 경우, A의 1번째를 참조하여 할당한 경우들에 대해서 모두 주소 값이 찍히지 않은 것을 볼 수 있다.
cout과 << 연산자 문제라고 생각할 수도 있었지만, 입출력 관련해서 char 타입이 문제가 많았던 것이 생각이 나서 char *가 문제인가 하는 생각이 먼저 들었다. 이에 따라 char *가 아닌 non-char 포인터에 대해서도 주소가 찍히지 않는가를 실험해보았다.
#include <iostream>
int main()
{
int A[100];
int *ptr;
ptr = A;
std::cout << ptr << std::endl;
ptr = &A[0];
std::cout << ptr << std::endl;
ptr = &A[1];
std::cout << ptr << std::endl;
return (0);
}
C++
복사
위의 그림을 보면 int * 타입으로 이용했을 때는 주소 값이 잘 찍히는 것을 볼 수 있었다. 왜 이번에도 cout에 대해서는 함수의 주소 출력 뿐 아니라 char *의 주소 출력에도 문제가 있는 것일까?
2. 문제 원인 및 해결 방법
char *로 된 포인터의 참조 값을 찍으려 했을 때 잘 되지 않았던 이유는 바로 iostream에서 ostream과 관련이 있다.
ostream이용 시에 C++은 char *를 string으로 인식하게 되는데 C++의 string 특성 상 문자열의 끝을 알리는 '\0'가 들어오지 않는 문자열이 끝이 났다고 인식하지 않는다. 따라서 주소가 출력되지 않고 빈 칸으로 출력된다. (C++에서 string은 '\0'이라고 하는 NULL이 들어오면 끝으로 인식하는 Zero-Terminated 구조이다.)
따라서 non-char 포인터인 int *, double * 등은 위와 같은 문제가 없지만 char*는 주소를 출력하려고 할 때, 문제가 발생하는 것이다.
성공적으로 주소를 출력하기 위해선 char * 타입의 변수를 non-char 포인터 타입으로 형 변환 해주면 되는데, 이에 대해선 Generic 타입이 가장 적합한 선택지이다. 따라서 std::cout << ptr << std::endl 할 때 ptr을 void *로 형 변환하면 된다.
포인터의 형 변환이므로 reinterpret_cast를 이용한다.
#include <iostream>
int main()
{
char A[100];
char *ptr;
ptr = A;
std::cout << reinterpret_cast<void *>(ptr) << std::endl;
ptr = &A[0];
std::cout << reinterpret_cast<void *>(ptr) << std::endl;
ptr = &A[1];
std::cout << reinterpret_cast<void *>(ptr) << std::endl;
return (0);
}
C++
복사
아래 그림과 같이 주소가 잘 출력되는 것을 볼 수 있다.