NULL, '\ 0'과 0의 차이점은 무엇입니까?


309

- C, 다양한 제로 값의 차이가있을 표시 NULL, NUL0.

ASCII 문자 '0'48또는로 평가 된다는 것을 알고 0x30있습니다.

NULL포인터는 일반적으로 다음과 같이 정의된다

#define NULL 0

또는

#define NULL (void *)0

덧붙여 평가하고 있는 NUL캐릭터 도 있습니다.'\0'0

이 세 가지 값이 같지 않을 때가 있습니까?

64 비트 시스템에서도 마찬가지입니까?


1
0과 NULL의 차이점에 대한 자세한 내용은 stackoverflow.com/questions/176989/… 를 참조하십시오 .
David Rodríguez-dribeas

7
식별자 NUL는 C 표준 언어 또는 라이브러리 (또는 내가 아는 한 C ++)에 존재하지 않습니다. 널 (null) 문자는 NUL이라고도하지만 C 또는 C ++에서는 보통 방금이라고합니다 '\0'.
키이스 톰슨

답변:


351

노트 : 이 답변은 C ++가 아닌 C 언어에 적용됩니다.


널 포인터

정수 상수 리터럴 0은 사용되는 컨텍스트에 따라 다른 의미를 갖습니다. 모든 경우에 여전히 값을 갖는 정수 상수입니다.0 이며 다른 방식으로 설명되어 있습니다.

포인터가 상수 리터럴과 비교되는 0경우 포인터가 널 포인터인지 확인합니다. 이것은 0다음 널 포인터 상수라고합니다. C 표준은 0유형에 캐스트되는 것을 정의합니다.void * 널 포인터 및 널 포인터 상수 .

또한 가독성을 높이기 위해 매크로 NULL가 헤더 파일에 제공됩니다 stddef.h. 컴파일러에 따라 다음이 가능할 수 있습니다.#undef NULL 이상한 것으로 다시 정의 할 .

따라서 다음은 널 포인터를 확인하는 올바른 방법입니다.

if (pointer == NULL)

NULL널 포인터와 동일하게 비교하도록 정의됩니다. NULL유효한 널 포인터 상수 인 한 실제 정의가 무엇인지 정의 된 구현 입니다.

if (pointer == 0)

0 널 포인터 상수의 다른 표현입니다.

if (!pointer)

if 문장은 "is not 0"을 암시 적으로 확인하므로 "is 0"을 의미하는 것으로 바 꾸었습니다.

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

int mynull = 0;
<some code>
if (pointer == mynull)

컴파일러에게 이것은 널 포인터 검사가 아니라 두 변수에 대한 동등 검사입니다. 이것은 아마도 작업 mynull가 결코 코드를 변경하지 않고 문 경우 컴파일러 최적화 상수가에 0 배,하지만이 보장되지 않으므로 컴파일러는 C 표준에 따라 적어도 하나의 진단 메시지 (경고 또는 오류)를 생산하는 경우.

C 언어에서 널 포인터는 무엇입니까? 기본 아키텍처에서는 중요하지 않습니다. 기본 아키텍처에 주소 0xDEADBEEF로 정의 된 널 포인터 값이있는 경우이 엉망을 분류하는 것은 컴파일러의 책임입니다.

따라서이 재미있는 아키텍처에서도 다음 방법은 여전히 ​​널 포인터를 확인하는 유효한 방법입니다.

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

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

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

이것들은 컴파일러에 의해 일반적인 비교로 볼 수 있습니다.

널 문자

'\0'은 널 문자로 정의됩니다. 즉, 모든 비트가 0으로 설정된 문자입니다. 이것은 포인터와 관련이 없습니다. 그러나이 코드와 비슷한 것을 볼 수 있습니다 :

if (!*string_pointer)

문자열 포인터가 널 문자를 가리키는 지 확인

if (*string_pointer)

문자열 포인터가 널이 아닌 문자를 가리키는 지 확인

널 포인터와 혼동하지 마십시오. 비트 표현이 동일하기 때문에 편리한 크로스 오버 케이스가 가능하기 때문에 실제로는 동일하지 않습니다.

또한 '\0'모든 문자 리터럴과 마찬가지로 정수 상수이며이 경우 값은 0입니다. 따라서 '\0'unadorned 0integer constant 와 완전히 동일 합니다. 유일한 차이점은 인간 독자에게 전달 하려는 의도 입니다 ( "Null 문자로 사용하고 있습니다").

참고 문헌

자세한 내용 은 comp.lang.c FAQ의 질문 5.3을 참조하십시오 . C 표준에 대해서는 이 pdf 를 참조하십시오 . 섹션 6.3.2.3 포인터, 단락 3을 확인하십시오.


3
FAQ 목록을 가리켜 주셔서 감사합니다. 그러나 또한 참조 c-faq.com/null/nullor0.html
신안 Ünür

4
아니, 당신은 비교하지 않습니다 ptr모든 비트 제로 . 이 제품에 대한 설명은 아직이다 memcmp, 그러나 이것은 내장 연산자를 사용하여 비교입니다. 한쪽은 널 포인터 상수 '\0'이고 다른 쪽은 포인터입니다. Aswell와 다른 두 버전으로 NULL0. 그 세 사람도 같은 일을합니다.
Johannes Schaub-litb

6
비트 스트링을 비교하는 것으로 내장 비교 연산자를 사용하고 있습니다. 그러나 그것이 아닙니다. 추상적 인 개념 인 두 가지 값을 비교합니다. 따라서 내부적으로 표시 0xDEADBEEF되는 널 포인터는 비트 열의 모양에 관계없이 여전히 널 포인터 NULL이며 0, \0및 다른 모든 널 포인터 상수 형식과 동일하게 비교됩니다 .
Johannes Schaub-litb

2
비교 연산자에 대해 좋은 지적을합니다. 나는 C99를 닦았다. "값이 0 인 정수 상수 표현식 또는 void * 유형으로 캐스트되는 표현식을 널 포인터 상수라고합니다." 또한 문자 리터럴은 정수 상수 표현식이라고 말합니다. 따라서 전이 속성에 의해 당신은 맞습니다 ptr == '\0'.
Andrew Keeton

2
".... NULL을 #undef하고 그것을 이상한 것으로 재정의하는 것이 가능할 수 있습니다. 내 좋은 선생님이 크게 웃게 만들었습니다 ...
oggiemc

34

많은 사람들이 NULL, '\ 0'및 0의 차이점이 무엇인지 오해하는 것으로 보입니다. 따라서 설명하고 반복하는 것을 피하기 위해 앞에서 말한 것을 반복하십시오.

int값이 0 인 유형의 상수 표현식 또는 유형으로 캐스트 된 유형 void *널 포인터 상수 이며, 포인터 로 변환되면 널 포인터가 됩니다. 표준에 의해 객체 나 함수에 대한 포인터와 다른 것을 비교하는 것이 보장됩니다 .

NULL널 포인터 상수 로 정의 된 매크로 입니다.

\0null 문자 를 나타내는 데 사용되는 구성으로 , 문자열을 종료하는 데 사용됩니다.

NULL 문자는 0으로 설정된 모든 비트를 갖는 바이트이다.


14

세 가지 모두 서로 다른 상황에서 0의 의미를 정의합니다.

  • 포인터 컨텍스트-NULL이 사용되며 포인터가 32 비트인지 64 비트인지에 상관없이 포인터 값이 0임을 의미합니다 (한 경우 4 바이트, 다른 8 바이트의 0).
  • 문자열 컨텍스트-숫자 0을 나타내는 문자는 16 진수 값이 0x30이고 NUL 문자는 16 진수 값이 0x00입니다 (문자열 종료에 사용됨).

이 세 가지는 항상 메모리를 볼 때 다릅니다.

NULL - 0x00000000 or 0x00000000'00000000 (32 vs 64 bit)
NUL - 0x00 or 0x0000 (ascii vs 2byte unicode)
'0' - 0x20

나는 이것이 그것을 명확히하기를 바랍니다.


8
나 스코 : 평가 sizeof('\0')하고 놀라십시오.
caf

3
@ Nasko : 정말 놀랐습니다 : gcc, C : sizeof ( '\ 0') == sizeof ( 'a') == 4, g ++에서는 C ++ : sizeof ( '\ 0') == sizeof ( 'a') == 1
David Rodríguez-dribeas

1
@ Nasko : C 표준 (draft, n1124)에서 : '정수 문자 상수에는 int 유형이 있습니다.'따라서 '\ 0'은 실제로 C의 int 유형이므로 내 아키텍처에서 sizeof ( '\ 0')는 4입니다. (linux, 32bit)
David Rodríguez-dribeas

@dribeas-상수로 묘사하지 않고 문자열의 일부로 볼 수 있습니다. 나는 분명히 그것을 명시 적으로 만들 수 있었다. 감사합니다
Nasko

@ DavidRodríguez-dribeas Undid edit " '0'ASCII 값을 0x20 (12 월 32 일로 수정)"
chux-복원 Monica Monica

6

NULL과 0이 널 포인터 상수와 같은 경우 어떤 것을 사용해야합니까? C FAQ 목록의이 문제도 해결합니다.

C 프로그래머는 것을 이해해야합니다 NULL0포인터 상황에서 상호 교환 및 uncast 그게 0 완벽하게 허용됩니다. NULL과 반대되는 사용법은 0포인터가 관련되어 있다는 것을 상기시켜주는 것으로 간주해야합니다. 프로그래머는 포인터 0와 정수 를 구별하기 위해 자신의 이해 나 컴파일러에 의존해서는 안됩니다 0.

포인터 컨텍스트에서만 존재 NULL하며 0이에 상응합니다. NULL다른 스타일 0이 필요한 경우 작동하지 않더라도 잘못된 스타일 메시지를 전송하므로 사용하지 않아야합니다. (또한, ANSI는 정의 할 수 NULL있을하는 ((void *)0)특히, 사용하지 않는 포인터가 아닌 상황에서 전혀없는 일. 예정) NULL는 ASCII 널 문자 (때 NUL) 원하는됩니다. 자신의 정의를 제공

#define NUL '\0'

당신이해야한다면.


5

NULL, '\ 0'과 0의 차이점은 무엇입니까?

"널 문자 (NUL)"는 배제하기가 가장 쉽습니다. '\0'문자 리터럴입니다. C에서는로 구현 int되므로 0과 동일 INT_TYPE_SIZE합니다. C ++에서 문자 리터럴 char은 1 바이트 인 로 구현됩니다 . 일반적으로 NULL또는0 .

다음, NULL 은 변수가 주소 공간을 가리 키지 않도록 지정하는 포인터 값입니다. 일반적으로 0으로 구현된다는 사실을 제외하고는 아키텍처의 전체 주소 공간을 표현할 수 있어야합니다. 따라서 32 비트 아키텍처에서 NULL은 4 바이트이고 64 비트 아키텍처에서 8 바이트입니다. 이것은 C의 구현에 달려 있습니다.

마지막으로 리터럴 0intsize INT_TYPE_SIZE입니다. 의 기본값 INT_TYPE_SIZE은 아키텍처에 따라 다를 수 있습니다.

애플은 다음과 같이 썼다.

Mac OS X에서 사용하는 64 비트 데이터 모델을 "LP64"라고합니다. 64 비트 Linux뿐만 아니라 Sun 및 SGI의 다른 64 비트 UNIX 시스템에서 사용하는 공통 데이터 모델입니다. LP64 데이터 모델은 다음과 같이 기본 유형을 정의합니다.

  • 정수는 32 비트입니다
  • long은 64 비트입니다
  • long-longs도 64 비트입니다
  • 포인터는 64 비트입니다

위키 백과 64 비트 :

Microsoft의 VC ++ 컴파일러는 LLP64 모델을 사용합니다.

64-bit data models
Data model short int long  long long pointers Sample operating systems
LLP64      16    32  32    64        64       Microsoft Win64 (X64/IA64)
LP64       16    32  64    64        64       Most Unix and Unix-like systems (Solaris, Linux, etc.)
ILP64      16    64  64    64        64       HAL
SILP64     64    64  64    64        64       ?

편집 : 문자 리터럴에 더 추가되었습니다.

#include <stdio.h>

int main(void) {
    printf("%d", sizeof('\0'));
    return 0;
}

위의 코드는 gcc에서 4를, g ++에서 1을 반환합니다.


2
아니요, 1 바이트 값 '\0'아닙니다 . 정수 상수 표현식 인 문자 리터럴입니다. 따라서 크기가 있다고 할 수있는 경우 크기는 int2 바이트 이상이어야합니다. 당신이 나를 믿지 않는다면, 평가 sizeof('\0')하고 스스로를 참조하십시오. '\0', 0그리고 0x0모두 완전히 동일합니다.
caf

@caf 언어에 따라 다릅니다. 나를 믿지 않는다면 sizeof('\0')C ++ 컴파일러를 사용해보십시오 .
유진 요코타

2
sizeof (something)을 인쇄 할 때 "% zu"를 사용해야합니다
사용하지 않은


4

C로 시작할 때 도움이되는 좋은 작품

하나의 'l'널과 두 개의 'l'널

이 작은 운율을 암기하여 포인터와 ASCII 0에 대한 올바른 용어를 상기하십시오.

The one "l" NUL ends an ASCII string,

The two "l" NULL points to no thing.

Apologies to Ogden Nash, but the three "l" nulll means check your spelling. 

비트 패턴이 0 인 ASCII 문자를 "NUL"이라고합니다. 포인터 포인트를 의미하는 특수 포인터 값은 "NULL"입니다. 두 용어는 의미가 서로 바뀌지 않습니다.


훨씬 간단 : NUL와 같은 제어 코드 인 BEL, VT, HT, SOT등이 이에 최대 갖는다. 3 자
glglgl

2

"NUL"은 0이 아니지만 ASCII NUL 문자를 나타냅니다. 적어도 그것이 내가 사용한 것을 보았습니다. 널 포인터는 종종 0으로 정의되지만 이는 실행중인 환경 및 사용중인 운영 체제 또는 언어의 스펙에 따라 다릅니다.

ANSI C에서 널 포인터는 정수 값 0으로 지정됩니다. 따라서 true가 아닌 모든 세계는 ANSI C와 호환되지 않습니다.


1

값이 바이트 인 0x00ASCII 테이블에서 NUL또는 특수 문자는 또는 NULL입니다. C에서는 소스 코드에 제어 문자를 포함해서는 안되므로 이스케이프가 0 인 C 문자열로 표시됩니다.\0 .

그러나 진정한 NULL은 아닙니다. 값 . 가치가 없다. 포인터의 경우 포인터가 가리킬 것이 없음을 의미합니다. 데이터베이스에서 이는 필드에 값이 없음을 의미합니다 (필드가 공백, 0 또는 공백으로 채워진 것과 동일하지 않음).

주어진 시스템 또는 데이터베이스 파일 형식 이 실제 값을 나타내는 NULL데 반드시 필요한 것은 아닙니다 0x00.


0

NULL0이 될 수는 없습니다. 정확한 값은 아키텍처에 따라 다릅니다. 대부분의 주요 아키텍처는이를 정의합니다 (void*)0.

'\0' 바이트 0이 문자 리터럴로 인코딩되는 방식이므로 항상 0과 같습니다.

내가 C 컴파일러를 사용하여 ASCII에 필요한지 여부를 기억하지 -하지 않을 경우 '0'에 관계없이 항상 48과 동일하지 않을 수 있습니다, 그것은 당신이 지금 작업중인 않는 EBCDIC과 같은 다른 문자 집합을 사용하는 시스템 발생할 것 같지도 매우를 모호한 시스템.

다양한 유형의 크기는 64 비트 시스템에서 다르지만 정수 값은 동일합니다.


일부 댓글이 NULL이 0과 동일 할 수 있지만 의심 표명 제로. 다음은 그러한 시스템에서 예상되는 출력과 함께 예제 프로그램입니다.

#include <stdio.h>

int main () {
    size_t ii;
    int *ptr = NULL;
    unsigned long *null_value = (unsigned long *)&ptr;
    if (NULL == 0) {
        printf ("NULL == 0\n"); }
    printf ("NULL = 0x");
    for (ii = 0; ii < sizeof (ptr); ii++) {
        printf ("%02X", null_value[ii]); }
    printf ("\n");
    return 0;
}

이 프로그램은 다음을 인쇄 할 수 있습니다.

NULL == 0
NULL = 0x00000001

2
영업 이익에 대해 질문했다 '\ 0'(널 (null) 문자)가 아닌 '0'(제로 문자)
크리스 루츠

2
@Chris : '\ 0'은 NULL이 아니며 문자 리터럴에서 8 진수로 바이트 0으로 인코딩됩니다.
John Millikin

2
C ++에서 표준은 정수 값 0에서 포인터로의 변환이 항상 널 포인터를 생성하도록 보장합니다. C ++에서 0은 널 포인터가되는 반면, NULL은 매크로이며 악의적 인 코더는이를 다른 것으로 재정의 할 수 있습니다.
David Rodríguez-dribeas

6
그리고 NULL은 0이 보장된다. NULL 포인터의 비트 패턴은 모두 0이 보장되지는 않지만 NULL 상수는 항상 0이 될 것이다.
jalf

2
첫 번째 문장이 잘못되었습니다. void C에서 다른 포인터로 암시 적 변환이 없기 때문에 C ++에서 NULL을 (void *) 0으로 정의 할 수 없습니다 (C와 달리).

-2

(void *) 0은 NULL이며 '\ 0'은 문자열의 끝을 나타냅니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.