IT TIP

'\ 0'과 NULL을 같은 의미로 사용할 수 있습니까?

itqueen 2021. 1. 6. 20:34
반응형

'\ 0'과 NULL을 같은 의미로 사용할 수 있습니까?


NULL은 포인터 컨텍스트에서 자주 사용되며 여러 표준 라이브러리 (예 :)의 매크로를 통해 <iostream>정수가되도록 정의 0됩니다. '\0'널 문자이고 8 비트의 0입니다. 덧붙여서, 0의 8 비트는 정수와 동일합니다 0.

어떤 경우에는 끔찍한 스타일로 간주되지만이 두 가지가 서로 바뀔 수 있습니다.

int *p='\0';
if (p==NULL) //evaluates to true
    cout << "equal\n";

또는

char a=NULL;
char b='\0';
if (a==b) //evaluates to true
    cout << "equal again\n";

SO만으로도 이미 많은 유사한 질문이 있습니다. 예를 들어이 질문에 대한 상위 답변 ( NULL, '\ 0'및 0의 차이점은 무엇입니까? )은 "그들은 실제로 같은 것이 아닙니다."라고 말합니다.

사람은 예를 들어 제공 할 수 NULL\0상호 교환 될 수 없다 (바람직 실제 응용 아니라 병리 경우)?


누구든지 NULL과 \ 0을 바꿀 수 없다는 예를 제공 할 수 있습니까?

의 차이 NULL와는 '\0'오버로드 확인에 영향을 미칠 수 있습니다.

예 ( Coliru에서 확인 ) :

#include <iostream>

// The overloaded function under question can be a constructor or 
// an overloaded operator, which would make this example less silly
void foo(char)   { std::cout << "foo(char)"  << std::endl; }
void foo(int)    { std::cout << "foo(int)"   << std::endl; }
void foo(long)   { std::cout << "foo(long)"  << std::endl; }
void foo(void*)  { std::cout << "foo(void*)" << std::endl; }

int main()
{
    foo('\0'); // this will definitely call foo(char)
    foo(NULL); // this, most probably, will not call foo(char)
}

Coliru에서 사용되는 gcc 컴파일러는 NULL정의합니다. 0L이 예 에서는 foo(NULL)해석 foo(long)되지 않습니다 foo(void*). 이 답변 은 그 측면에 대해 자세히 설명합니다.


C ++에서 매크로 NULL의 정의

Leon은 동일한 함수에 대해 여러 오버로드가있을 때 \0유형의 매개 변수를 취하는 것을 선호 한다는 것이 맞습니다char . 그러나 일반적인 컴파일러에서 NULL유형 int이 아닌 유형의 매개 변수를 사용하는 오버로드를 선호한다는 점에 유의해야 합니다 void*.

이 혼란을 일으키는 원인은 C 언어 NULL(void*)0. C ++ 표준은 다음과 같이 명시합니다 (초안 N3936, 페이지 444) :

[매크로의 가능한 정의 NULL] 포함 0하고 0L있지만 (void*)0.

예를 들어 char *p = (void*)0유효한 C이지만 유효하지 않은 C ++ 인 반면 char *p = 0두 가지 모두에서 유효 하기 때문에 이러한 제한이 필요 합니다.

C ++ 11 이상에서는 nullptr포인터로 작동하는 null 상수가 필요한 경우를 사용해야합니다.

Leon의 제안이 실제로 작동하는 방식

이 코드는 단일 함수의 여러 오버로드를 정의합니다. 각 과부하는 매개 변수 유형을 출력합니다.

#include <iostream>

void f(int) {
    std::cout << "int" << std::endl;
}

void f(long) {
    std::cout << "long" << std::endl;
}

void f(char) {
    std::cout << "char" << std::endl;
}

void f(void*) {
    std::cout << "void*" << std::endl;
}

int main() {
    f(0);
    f(NULL);
    f('\0');
    f(nullptr);
}

Ideone 에서이 출력

int
int
char
void*

따라서 과부하 문제는 실제 적용이 아니라 병리학적인 경우라고 주장합니다. NULL상수는 잘못 어쨌든 행동하며, 교체해야 nullptr(11) C ++로.

NULL이 0이 아니면 어떻게됩니까?

Andrew Keeton 이 또 다른 질문에서 또 다른 병리학적인 사례 를 제안했습니다 .

C 언어에서 널 포인터가 무엇인지 유의하십시오. 기본 아키텍처에서는 중요하지 않습니다. 기본 아키텍처에 주소 0xDEADBEEF로 정의 된 널 포인터 값이있는 경우이 문제를 정렬하는 것은 컴파일러에 달려 있습니다.

따라서이 재미있는 아키텍처에서도 다음과 같은 방법으로 null 포인터를 확인할 수 있습니다.

if (!pointer)
if (pointer == NULL)
if (pointer == 0)

다음은 널 포인터를 확인하는 잘못된 방법입니다.

#define MYNULL (void *) 0xDEADBEEF
if (pointer == MYNULL)
if (pointer == 0xDEADBEEF)

이들은 컴파일러에서 일반적인 비교로 간주됩니다.

요약

대체로 차이점은 대부분 문체라고 말할 수 있습니다. 를 취하는 함수가 int있고를받는 오버로드가 char있고 함수가 다르게 작동하는 경우 \0NULL상수를 사용 하여 호출 할 때 차이가 있음을 알 수 있습니다 . 그러나 이러한 상수를 변수에 배치하면 호출 된 함수가 변수 유형에서 공제되기 때문에 차이가 사라집니다.

올바른 상수를 사용하면 코드를 더 쉽게 유지할 수 있고 의미를 더 잘 전달할 수 있습니다. 당신은 사용해야 0당신이 수를 의미 할 때, \0당신은 문자를 의미 할 때, 그리고 nullptr때 포인터를 의미한다. 마티유 M.가 있다는 의견에 지적 GCC 버그했다 A를하는, char*비교되었다 \0의도가 포인터를 역 참조하는 것이었다과 비교 반면 char\0. 코드베이스 전체에서 적절한 스타일을 사용하면 이러한 오류를 감지하기가 더 쉽습니다.

귀하의 질문에 대답하기 위해, 정말 사용하지 못하도록하는 것 실제 사용 사례가없는 \0NULL상호 교환. 문체적인 이유와 일부 엣지 케이스.


Please don't do this. It is an anti-pattern, and it is actually wrong. NULL is for NULL pointers, '\0' is the null-character. They are logically different things.

I don't think I have ever seen this:

int* pVal='\0';

But this is fairly common:

char a=NULL;

But it is not good form. It makes the code less portable, and in my opinion less readable. It is also likely to cause issues in mixed C/C++ environments.

It relies on assumptions regarding how any particular implementation defines NULL. For instance, some implementations use a simple

#define NULL 0

Others might use:

#define NULL ((void*) 0)

And I have seen others defining as an integer, and all sorts of odd treatment.

NULL should, in my opinion be used solely to indicate an invalid address. If you want a null-character, use '\0'. Or define this as NULLCHR. But that isn't as clean.

This will make your code more portable- you won't start getting warnings regarding types etc if you change compiler / environment /compiler settings. This might be more important in a C or mixed C/C++ environment.

An example of warnings that might arise: Consider this code:

#define NULL 0
char str[8];
str[0]=NULL;

This is equivalent to:

#define NULL 0
char str[8];
str[0]=0;

And we are assigning an integer value to a char. This may cause a compiler warning, and if there are enough occurrences of this, pretty soon you can't see any important warnings. And for me, this is the real problem. Having warnings in the code has two side effects:

  1. Given enough warnings, you don't spot new ones.
  2. It gives the signal that warnings are acceptable.

In both cases, actual bugs can then slip through, that would be caught by the compiler had we bothered to read the warnings (or turn on -Werror )


Yes, they may exhibit different behaviour while doing resolution of overloaded functions.

func('\0') invokes func(char),

while

func(NULL) invokes func(integer_type).


You can remove the confusion by using nullptr, which is always a pointer type, displays no ambiguity while assigning/comparing value or function overloading resolution.

char a = nullptr; //error : cannot convert 'std::nullptr_t' to 'char' in initialization
int x = nullptr;  //error : nullptr is a pointer not an integer

Note that, it is still compatible with NULL:

int *p=nullptr;
if (p==NULL) //evaluates to true

Excerpt from C++ Programming Stroustrup 4th Edition book:

In older code, 0 or NULL is typically used instead of nullptr (§7.2.2). However, using nullptr eliminates potential confusion between integers (such as 0 or NULL) and pointers (such as nullptr).



Computer programs have two types of readers.

The first type are computer programs, like the compiler.

The second type are humans, like yourself and your coworkers.

Programs are generally fine with getting one type of zero in place of another. There are exceptions, as the other answers have pointed out, but that is not really important.

What is important is that you are messing with the human readers.

Human readers are very context sensitive. By using the wrong zero, you are lying to you human readers. They are going to curse you.

A human that is lied to can overlook bugs more easily.
A human that is lied to can see "bugs" that aren't there. When "fixing" these phanthom bugs, they introduce real bugs.

Don't lie to your humans. One of the humans you are lying to is your future self. You are going to curse you too.


Excerpts from C++14 draft N3936:

18.2 Types [support.types]

3 The macro NULL is an implementation-defined C++ null pointer constant in this International Standard (4.10).

4.10 Pointer conversions [conv.ptr]

1 A null pointer constant is an integer literal (2.14.2) with value zero or a prvalue of type std::nullptr_t.
A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type.

Thus, NULL can be any integer literal with value zero, or a value of type std::nullptr_t like nullptr, while '\0' is always the zero narrow-character literal.

So, not in general interchangeable, even though in a pointer-context you cannot see any but stylistic difference.

An example would be:

#include <iostream>
#include <typeinfo>

int main() {
    std::cout << typeid('\0').name << '\n'
        << typeid(NULL).name << '\n'
        << typeid(nullptr).name << '\n';
}

Let's define what's NULL in C/C++.

According to the C/C++ reference NULL is defined as a macro that expands to a null pointer constant. Next we can read that a null pointer constant can be converted to any pointer type (or pointer-to-member type), which acquires a null pointer value. This is a special value that indicates that the pointer is not pointing to any object.

Definition referring to C:

A null-pointer constant is an integral constant expression that evaluates to zero (like 0 or 0L), or the cast of such value to type void* (like (void*)0).

Definition referring to C++98:

A null-pointer constant is an integral constant expression that evaluates to zero (such as 0 or 0L).

Definition referring to C++11:

A null-pointer constant is either an integral constant expression that evaluates to zero (such as 0 or 0L), or a value of type nullptr_t (such as nullptr).

Overloading methods example.

Let's assume that we have following methods:

class Test {
public:
    method1(char arg0);
    method1(int arg0);
    method1(void* arg0);
    method1(bool arg0);
}

Calling method1 with argument NULL or nullptr should call method1(void* arg0);. However if we call method1 with argument '\0' or 0 should execute method1(char arg0); and method1(int arg0);.

ReferenceURL : https://stackoverflow.com/questions/40395066/can-0-and-null-be-used-interchangeably

반응형