NULL - 널 포인터

NULL의 정의를 보면 포인터가 아니라 매크로에서 정의된 상수 0

#ifndef NULL
    #ifdef __cplusplus
        #define NULL 0
    #else
        #define NULL ((void *)0)
    #endif
#endif

C에선 ((void *)0) 으로 사용하고, C++ 에선 0 으로 사용한다.

 

NULL을 널 포인터 (주소가 없다는 것을 의미) 로 사용하였지만 0 이라는 정수로 인식되는 문제가 있음

포인터 변수에 넣으면 0x0 주소를 넣는 용도로 사용하였지만, 일반 변수에도 넣을 수 있었다.

char* ptr = NULL;
int a = NULL;

때문에 nullptr 이 생김

 

nullptr은 포인터의 변환을 허락하면서 다른 기능을 차단하는 const object

// nullptr 구현 예시
class Nullptr
{
public:
	// 일반 변수형에 대입 가능
    //template<typename T>
    //operator T () const
    //{
    //    return 0;
    //}

    // 어떠한 타입의 포인터라도 대입 가능
    template<typename T>
    operator T* () const
    {
        return 0;
    }

    // 그 어떤 타입의 멤버 포인터와도 치환 가능
    template<typename C, typename T>
    operator T C::* () const
    {
        return 0;
    }

    // 주소값 유출을 막는다
    void operator&() const = delete;
};

const Nullptr _nullptr;


A* a = _nullptr;
int* b = _nullptr;
int c = _nullptr; // error

결국 nullptr 도 0 을 반환하긴 하지만, 포인터에 대해서만 사용할 수 있다. 

 

NULL nullptr
널 포인터 - 주소가 없다는 것을 의미인 0을 반환
일반형 / 포인터 모두 사용 가능

정수 0
주소 0x0

둘 다 인식
포인터에만 사용 가능

주소 0x0 만 인식

 

 

#include <iostream>

using namespace std;

int Integer, *Pointer;

void print(int ptr) {
 	Integer = ptr;
 	cout << "integer : " << ptr << endl;
}

void print(int* ptr) {
	Pointer = ptr;
	cout << "pointer : " << ptr << endl;
}

int main() {
	Pointer = &Integer;
	print(10);      // print(int ptr)
	print(NULL);    // print(int ptr) print(int* ptr) ambiguous
	print(nullptr); // print(int* ptr)
}

print(10)

 


 

print(NULL)

함수 두개 모두 존재할때

 

void print(int ptr) 만 존재할 경우

 

 

void print(int* ptr) 만 존재할 경우

 

 

print(nullptr) 로 실행할 경우

 

 

print(10) => print(int ptr)

print(NULL) => print(int ptr) , print(int* ptr) 둘 다 가능

print(nullptr) => print(int* ptr)

 

 

c++에서는 NULL을 포인터가 아니라 정수 0과 동일하게 여긴다고 한다.

오버로딩 시, 프로그래머의 의도와 다른 함수가 호출될수도있다. (물론 함수에 NULL이나 nullptr을 인자로 받을 일은 거의 없다)

최근 실무에서도 포인터 변수를 초기화할때 NULL대신에 nullptr로 초기화는 많이 하는 추세라고함.

 

즉, 포인터만 사용할수있는 위치에 0이있으면 c++은 그것을 널 포인터로 해석하긴하지만 의도와 다르게 사용될수있다.

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

this 포인터, 연산자 오버로딩  (0) 2022.04.15
멤버 초기화 리스트, 이니셜라이저  (0) 2022.04.13
const / constexpr / #define  (0) 2022.04.12
C++ 상속  (0) 2022.04.08
virtual, override  (0) 2022.03.16

+ Recent posts