programing

null 포인터가 모든 비트0이 아닐 때 C/C++ 코드를 올바르게 쓰는 방법

nicescript 2022. 7. 6. 22:21
반응형

null 포인터가 모든 비트0이 아닐 때 C/C++ 코드를 올바르게 쓰는 방법

comp.lang.c FAQ에서 알 수 있듯이 늘 포인터가 모든 비트0이 아닌 아키텍처가 있습니다.따라서 실제로 다음 구조를 점검하는 것이 무엇인지에 대한 질문입니다.

void* p = get_some_pointer();
if (!p)
    return;

비교하고 있나요?p머신 의존형 늘 포인터 또는 비교하고 있습니다.p산술 0으로요?

쓸까요?

void* p = get_some_pointer();
if (NULL == p)
    return;

그런 건축물에 대비하는 게 낫지 않을까? 아니면 편집증 때문일까?

C 사양에 따라:

값이 0인 정수 상수 표현식 또는 void* 타입으로 주조된 표현식을 null 포인터 상수라고 부릅니다.55) null 포인터 상수가 포인터 타입으로 변환되면 null 포인터라고 불리는 결과 포인터는 객체 또는 함수에 대한 포인터와 동등하지 않음을 보증합니다.

그렇게0는 늘 포인터 상수입니다.또한 이를 포인터 유형으로 변환하면 일부 아키텍처에서는 null 포인터가 모두 0이 아닐 수 있습니다.다음으로 포인터와 늘 포인터 상수를 비교하는 방법에 대해 설명하겠습니다.

한 오퍼랜드가 포인터이고 다른 오퍼랜드가 늘 포인터 상수일 경우 늘 포인터 상수는 포인터 유형으로 변환됩니다.

생각해 봅시다(p == 0): 첫 번째0null 포인터로 변환되어p는 실제 비트값이 아키텍처에 따라 달라지는 늘 포인터 상수와 비교됩니다.

다음으로 사양에서 부정 연산자에 대해 뭐라고 하는지 살펴봅니다.

논리 부정 연산자 !의 결과는 피연산자 값이 0과 동일하지 않으면 0, 피연산자 값이 0과 같으면 1이 됩니다.결과는 int 타입입니다.식!E는 (0==E)와 같습니다.

즉,(!p)와 동등하다(p == 0)사양에 따르면, 테스트라고 합니다.p기계 정의 Null 포인터 상수에 대한 값입니다.

따라서, 당신은 안전하게 글을 쓸 수 있다.if (!p)null 포인터 상수가 all-bits-zero가 아닌 아키텍처에서도 마찬가지입니다.

C++의 경우 늘 포인터 상수는 다음과 같이 정의됩니다.

늘 포인터 상수는 0으로 평가되는 정수 유형의 정수 상수식(5.19) pr 값 또는 std::nullptr_t 유형의 pr 값입니다.늘 포인터 상수는 포인터 유형으로 변환할 수 있습니다.그 결과 해당 유형의 늘 포인터 값이 되며 오브젝트 포인터 또는 함수 포인터 유형의 다른 모든 값과 구별할 수 있습니다.

우리가 가진 C와 거의 비슷한 수준이죠nullptr구문설탕연산자의 동작==다음 항목에 의해 정의됩니다.

또한 멤버에 대한 포인터 또는 멤버에 대한 포인터와 늘 포인터 상수를 비교할 수 있습니다.멤버 변환(4.11) 및 자격 변환(4.4)에 대한 포인터가 실행되어 공통 유형이 됩니다.하나의 오퍼랜드가 늘 포인터 상수일 경우 공통 유형은 다른 오퍼랜드의 유형입니다.그 이외의 경우 공통 타입은 오퍼랜드타입의 cv 수식 시그니처의 조합인 cv 수식 시그니처(4.4)와 같은 멤버타입(4.4) 포인터입니다.[주의: 이는 멤버에 대한 포인터를 늘 포인터 상수와 비교할 수 있음을 의미합니다.- 종료 노트 ]

그것은 의 전환으로 이어진다.0(C의 경우) 포인터 타입으로 변환합니다.부정 연산자의 경우:

논리 부정 연산자 !의 피연산자는 컨텍스트적으로 bool(Clause 4)로 변환됩니다.변환된 피연산자가 true이면 값이 true이고 그렇지 않으면 false입니다.그 결과의 종류는 bool이다.

즉, 그 결과는!p포인터에서 포인터로 변환하는 방법에 따라 다르다bool실행됩니다.표준에는 다음과 같이 기술되어 있습니다.

제로 값, 늘 포인터 값 또는 늘 멤버 포인터 값이 false로 변환됩니다.

그렇게if (p==NULL)그리고.if (!p)C++에서도 같은 동작을 합니다.

null 포인터가 실제 머신에서는 모두 비트0 이든 아니든 상관없습니다.가정하다p는 포인터입니다.

if (!p) 

항상 합법적으로 테스트하는 방법입니다.p는 늘 포인터이며 항상 다음과 같습니다.

if (p == NULL)

다른 C-FAQ 기사에 관심이 있을 수 있습니다.이거 이상하다. NULL은 0으로 보장되지만 NULL 포인터는 그렇지 않습니다.


위의 내용은 C와 C++ 모두에 해당됩니다.C++(11)에서는 다음 명령어를 사용하는 것이 좋습니다.nullptrnull 포인터 리터럴의 경우.

이 답변은 C에 적용됩니다.

뒤섞이지 마NULLnull 포인터를 사용합니다. NULL는 늘 포인터 상수를 보증하는 매크로에 불과합니다.null 포인터 상수는 다음 중 하나입니다.0또는(void*)0.

C11 6.3.2.3부터:

값이 0인 정수 상수식 또는 void* 타입으로 주조된 식을 늘 포인터 상수 66이라고 합니다.늘 포인터 상수가 포인터 타입으로 변환되면 늘 포인터라고 불리는 결과 포인터는 오브젝트 또는 함수에 대한 포인터와 동등하지 않음을 보증합니다.

66) 매크로 NULL은 <stdef>에 정의되어 있습니다.(및 기타 헤더)를 늘 포인터 상수로 지정합니다(7.19 참조).

7.19:

매크로는

특수한 순서

구현 정의 늘 포인터 상수로 확장됩니다.

다음과 같은 경우에 구현 정의:NULL는 다음 중 하나입니다.0또는(void*)0.NULL다른 어떤 것도 될 수 없어요.

단, 늘 포인터 상수가 포인터에 할당되면 늘 포인터 상수와 비교해도 값이 0이 아닐 수 있습니다.코드if (!p)와는 전혀 관계가 없다NULL매크로에서는 늘 포인터를 산술값 0과 비교하고 있습니다.

그래서 이론적으로, 코드는int* p = NULLnull 포인터가 될 수 있습니다.p0이랑은 다르죠

옛날에는 STRATUS 컴퓨터에는 늘 포인터가 모든 언어로 1로 되어 있었습니다.

이로 인해 C에 문제가 발생했기 때문에 C 컴파일러는 0과 1의 포인터 비교를 통해 true를 반환할 수 있습니다.

이것은 다음을 가능하게 합니다.

void * ptr=some_func();
if (!ptr)
{
    return;
}

로.returnNull ptr에 있는 것은 알 수 있지만ptr디버거에서 값이 1이었다.

if ((void *)0 == (void *)1)
{
    printf("Welcome to STRATUS\n");
}

실제로 "Stratus에 오신 것을 환영합니다"라고 인쇄할까요?

컴파일러가 조금이라도 훌륭하다면 주의할 점은 두 가지입니다.

1: 초기화된(즉 할당되지 않은) 정적 기본 포인터에는 NULL이 없습니다.

2: memset()은 구조체 또는 배열상의 또는 확장 calloc()에 의해 포인터가 NULL로 설정되지 않습니다.

언급URL : https://stackoverflow.com/questions/32136092/how-to-write-c-c-code-correctly-when-null-pointer-is-not-all-bits-zero

반응형