Computer >> 컴퓨터 >  >> 프로그래밍 >> C 프로그래밍

C와 C++에서 NULL 포인터 정의가 다른 이유

C와 C++은 문법이 매우 비슷해 보이지만, NULL 포인터 상수(null pointer constant)를 정의하는 방식에는 미묘하면서도 중요한 차이가 있습니다. 이 차이는 두 언어의 타입 시스템 설계 철학에서 비롯된 것입니다.

C++에서의 NULL 포인터

C++에서 널 포인터 상수는 값이 0인 정수 상수 표현식(integer constant expression)으로 정의됩니다. 예를 들어 다음과 같이 작성할 수 있습니다.

int* p = 0;

여기서 주목할 점은 C++에서는 (void*)0 형태의 캐스팅을 널 포인터 상수로 인정하지 않는다는 것입니다. 그 이유는 C++이 타입 안전성(type safety)을 중시하기 때문입니다. C++에서는 void* 포인터를 다른 포인터 타입으로 암시적으로 변환할 수 없으므로, 명시적인 캐스팅 없이는 대입 자체가 허용되지 않습니다.

C에서의 NULL 포인터

반면 C 언어에서는 널 포인터 상수가 값이 0인 정수 상수 표현식이거나, 그러한 표현식을 void*로 캐스팅한 값 모두 가능합니다.

int* p = 0;

또는 다음과 같이 작성할 수도 있습니다.

int* p = (void*)0;

C에서는 void*에서 임의의 객체 포인터 타입으로의 암시적 변환이 허용되기 때문에 두 방식 모두 유효합니다.

C++11의 nullptr 키워드

C++11부터는 숫자 0 대신 사용할 수 있는 전용 키워드 nullptr가 도입되었습니다. nullptrstd::nullptr_t 타입을 가지며, 어떤 포인터 타입으로든 변환될 수 있지만 정수로는 해석되지 않습니다. 이를 통해 함수 오버로딩 시 발생할 수 있는 모호함(예: f(0) 호출 시 f(int)f(int*) 중 무엇이 선택될지 불분명한 문제)을 해결할 수 있습니다.

int* ptr = nullptr;

C 예제 코드

#include <stdio.h>

int main() {
    int *p = NULL; // 포인터를 NULL로 초기화
    printf("포인터의 값은 %u\n", p);
    return 0;
}

실행 결과

포인터의 값은 0

C++ 예제 코드

#include <iostream>
using namespace std;

int main() {
    int *p = NULL; // 포인터를 NULL로 초기화
    cout << "포인터의 값은 ";
    cout << p;
    return 0;
}

실행 결과

포인터의 값은 0

정리

  • C: 널 포인터 상수는 0 또는 (void*)0 모두 허용됩니다.
  • C++: 널 포인터 상수는 0만 허용되며, (void*)0은 널 포인터 상수로 간주되지 않습니다.
  • C++11 이후: 타입 안전성을 보장하는 nullptr 키워드 사용이 권장됩니다.

결국 이 차이는 C++이 C보다 엄격한 타입 검사를 채택하면서 생긴 것이며, 현대 C++ 코드에서는 가독성과 안전성을 위해 NULL이나 0 대신 nullptr을 사용하는 것이 가장 좋은 습관입니다.