널 포인터가 모든 비트가 0이 아닐 때 C / C ++ 코드를 올바르게 작성하는 방법
는 AS 때 comp.lang.c 자주 묻는 질문은 말한다 널 포인터가 아닌 모든 비트가 제로 곳, 아키텍처가 있습니다. 따라서 질문은 실제로 다음 구성을 확인하는 것입니다.
void* p = get_some_pointer();
if (!p)
return;
나는 비교 건가요 p
기계에 의존하는 널 포인터 또는 나는 비교하고있어 p
산술 0으로?
내가 써야 할까
void* p = get_some_pointer();
if (NULL == p)
return;
대신 그러한 아키텍처에 대한 준비가 되었습니까 아니면 단지 편집증입니까?
C 사양에 따르면 :
값이 0 인 정수 상수 표현식 또는 void * 유형으로 캐스트 된 이러한 표현식을 널 포인터 상수라고합니다. 55) 널 포인터 상수가 포인터 유형으로 변환되면 널 포인터라고하는 결과 포인터는 객체 또는 함수에 대한 포인터와 같지 않은 비교를 보장합니다.
그래서 0
null 포인터 상수입니다. 그리고 그것을 포인터 유형으로 변환하면 일부 아키텍처에서 모든 비트가 0이 아닌 널 포인터를 얻을 수 있습니다. 다음으로 스펙이 포인터와 널 포인터 상수를 비교하는 것에 대해 말하는 것을 보자 :
한 피연산자가 포인터이고 다른 피연산자가 널 포인터 상수 인 경우 널 포인터 상수는 포인터 유형으로 변환됩니다.
고려해 봅시다 (p == 0)
: 먼저 0
널 포인터로 변환 된 다음 p
실제 비트 값이 아키텍처에 따라 달라지는 널 포인터 상수와 비교됩니다.
다음으로 사양이 부정 연산자에 대해 말하는 내용을 확인합니다.
논리 부정 연산자의 결과! 피연산자의 값이 0과 같지 않으면 0, 피연산자의 값이 0과 같으면 1입니다. 결과 유형은 int입니다. ! E 표현식은 (0 == E)와 같습니다.
이는 사양 에 따라 기계 정의 널 포인터 상수에 대해 테스트하는 (!p)
것과 동일 함을 의미합니다 .(p == 0)
p
따라서 if (!p)
널 포인터 상수가 모두 0 비트가 아닌 아키텍처에서도 안전하게 작성할 수 있습니다 .
C ++의 경우 널 포인터 상수는 다음과 같이 정의됩니다.
널 포인터 상수는 0 또는 std :: nullptr_t 유형의 prvalue로 평가되는 정수 유형의 정수 상수 표현식 (5.19) prvalue입니다. 널 포인터 상수는 포인터 유형으로 변환 될 수 있습니다. 결과는 해당 유형의 널 포인터 값이며 오브젝트 포인터 또는 함수 포인터 유형의 다른 모든 값과 구별 할 수 있습니다.
C에 대해 우리가 가진 것과 nullptr
구문 설탕에 가깝습니다 . 연산자의 동작 ==
은 다음과 같이 정의됩니다.
또한 멤버에 대한 포인터를 비교하거나 멤버에 대한 포인터와 널 포인터 상수를 비교할 수 있습니다. 멤버에 대한 포인터 변환 (4.11) 및 자격 변환 (4.4)은 공통 유형으로 가져 오기 위해 수행됩니다. 한 피연산자가 널 포인터 상수이면 공통 유형은 다른 피연산자의 유형입니다. 그렇지 않으면 공통 유형은 피연산자 유형의 cv-qualification 서명의 합집합 인 cv-qualification 서명 (4.4)과 함께 피연산자 중 하나의 유형과 유사한 멤버 유형 (4.4)에 대한 포인터입니다. [참고 : 이는 멤버에 대한 모든 포인터가 널 포인터 상수와 비교할 수 있음을 의미합니다. — 끝 참고]
그러면 0
포인터 유형 으로 변환 됩니다 (C의 경우). 부정 연산자의 경우 :
논리 부정 연산자의 피연산자! 상황에 따라 bool로 변환됩니다 (4 절). 그 값은 변환 된 피연산자가 참이면 참이고 그렇지 않으면 거짓입니다. 결과 유형은 bool입니다.
즉, 결과는 !p
포인터에서 로의 변환 bool
이 수행되는 방식 에 따라 달라집니다 . 표준은 다음과 같이 말합니다.
0 값, 널 포인터 값 또는 널 멤버 포인터 값은 false로 변환됩니다.
그래서 if (p==NULL)
하고 if (!p)
너무 ++ C에서 같은 일을한다.
널 포인터가 모든 비트가 0인지 실제 머신에 있는지는 중요하지 않습니다. p
포인터 라고 가정 합니다.
if (!p)
는 항상 p
null 포인터 인지 테스트하는 합법적 인 방법 이며 항상 다음과 동일합니다.
if (p == NULL)
다른 C-FAQ 기사에 관심이있을 수 있습니다. 이것은 이상합니다. NULL은 0이 보장되지만 널 포인터는 그렇지 않습니까?
위의 내용은 C와 C ++ 모두에 해당됩니다. C ++ (11)에서는 nullptr
null 포인터 리터럴 에 사용하는 것이 좋습니다 .
이 답변은 C에 적용됩니다.
NULL
널 포인터와 혼동 하지 마십시오 . 널 포인터 상수가NULL
보장되는 매크로 일뿐 입니다. 널 포인터 상수는 또는 입니다.0
(void*)0
C11 6.3.2.3에서 :
값이 0 인 정수 상수 표현식 또는 void * 유형으로 캐스트 된 이러한 표현식을 널 포인터 상수 66)이라고합니다. 널 포인터 상수가 포인터 유형으로 변환되면 널 포인터라고하는 결과 포인터는 오브젝트 또는 함수에 대한 포인터와 같지 않은 비교를 보장합니다.
66) 매크로 NULL은 <stddef.h> (및 기타 헤더)에서 널 포인터 상수로 정의됩니다. 7.19 참조.
7.19 :
매크로는
없는
구현 정의 널 포인터 상수로 확장됩니다.
의 경우 구현 정의 NULL
가 0
또는 (void*)0
입니다. NULL
다른 것이 될 수 없습니다.
그러나 널 포인터 상수가 포인터에 할당되면 널 포인터 상수와 동일하게 비교하더라도 값이 0이 아닐 수있는 널 포인터 를 얻습니다 . 코드 if (!p)
는 NULL
매크로 와 관련이 없으며 널 포인터를 산술 값 0과 비교합니다.
따라서 이론적으로 같은 코드 는 0과 다른 int* p = NULL
널 포인터 p
를 생성 할 수 있습니다 .
Back in the day, STRATUS computers had null pointers as 1 in all languages.
This caused issues for C, so their C compiler would allow pointer comparison of 0 and 1 to return true
This would allow:
void * ptr=some_func();
if (!ptr)
{
return;
}
To return
on a null ptr even though you could see that ptr
had a value of 1 in the debugger
if ((void *)0 == (void *)1)
{
printf("Welcome to STRATUS\n");
}
Would in fact print "Welcome to STRATUS"
If your compiler is any good there are two things (and only two things) to watch out for.
1: Static default initialized (that is, not assigned) pointers won't have NULL in them.
2: memset() on a struct or array or by extension calloc() won't set pointers to NULL.
'IT박스' 카테고리의 다른 글
JavaScript의 스크립트 태그에서 JSON을 어떻게 읽을 수 있습니까? (0) | 2020.11.04 |
---|---|
MySQL : 최신 기록 가져 오기 (0) | 2020.11.04 |
Python을 사용하여 볼륨에 남아있는 교차 플랫폼 공간 (0) | 2020.11.04 |
하드웨어 설명 언어 (Verilog, VHDL 등)에 대한 모범 사례는 무엇입니까? (0) | 2020.11.04 |
자바 스크립트; (0) | 2020.11.04 |