NULL、 '\ 0'、0の違いは何ですか?


309

- Cにおいては、様々なゼロの値の差があるように思われるNULLNUL0

ASCII文字'0'48またはに評価されることを知ってい0x30ます。

NULLポインタは、通常のように定義されます。

#define NULL 0

または

#define NULL (void *)0

また、評価しそうNULなキャラもいます。'\0'0

これら3つの値が等しくない場合がありますか?

これは64ビットシステムにも当てはまりますか?


1
0とNULLの違いの詳細については、stackoverflow.com / questions / 176989 /…を参照してください。
デビッドロドリゲス-ドリベス

7
識別子NULは、C標準言語またはライブラリ(または私の知る限りではC ++)には存在しません。null文字はNULと呼ばれることもありますが、CまたはC ++は通常と呼ばれ'\0'ます。
キーストンプソン

回答:


351

注:この回答は、C ++ではなくC言語に適用されます。


ヌルポインター

整数定数リテラル0は、それが使用されるコンテキストに応じて異なる意味を持ちます。いずれの場合も、値は整数定数であり0、さまざまな方法で説明されています。

ポインターが定数リテラルと比較されている場合、0これはポインターがnullポインターかどうかを確認するチェックです。これ0は、NULLポインター定数と呼ばれます。C標準では0、型へのキャストvoid *はnullポインターとnullポインター定数の両方であると定義されています。

さらに、読みやすくするために、マクロNULLはヘッダーファイルで提供されますstddef.h。コンパイラによっては、#undef NULL奇抜なものに再定義できる場合があります。

したがって、ヌルポインターをチェックするいくつかの有効な方法を次に示します。

if (pointer == NULL)

NULLnullポインタと等しいと比較するように定義されています。これはNULL、有効なnullポインター定数である限り、実際の定義が何であるかを定義した実装です。

if (pointer == 0)

0 NULLポインター定数の別の表現です。

if (!pointer)

このifステートメントは暗黙的に「is not 0」をチェックするので、「is 0 "を意味するように逆にします。

以下は、ヌルポインターをチェックする無効な方法です。

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

コンパイラにとって、これはnullポインタのチェックではなく、2つの変数の等価チェックです。これ、mynullがコードで変更されず、コンパイラー最適化定数が0をifステートメントに折りたたむ場合に機能する可能性がありますが、これは保証されず、コンパイラーはC標準に従って少なくとも1つの診断メッセージ(警告またはエラー)を生成する必要があります。

C言語でのnullポインターとは何ですか。基盤となるアーキテクチャには関係ありません。基盤となるアーキテクチャにアドレス0xDEADBEEFとして定義されているnullポインター値がある場合、この混乱を取り除くのはコンパイラー次第です。

そのため、このおかしいアーキテクチャでも、次の方法はnullポインターをチェックする有効な方法です。

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

以下は、ヌルポインターをチェックする無効な方法です。

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

これらは通常の比較としてコンパイラによって見られるので。

ヌル文字

'\0'ヌル文字として定義されています-つまり、すべてのビットがゼロに設定された文字です。これはポインタとは関係ありません。ただし、次のようなコードが表示される場合があります。

if (!*string_pointer)

文字列ポインタがnull文字を指しているかどうかを調べます

if (*string_pointer)

文字列ポインタがnull以外の文字を指しているかどうかを調べます

これらをnullポインターと混同しないでください。ビット表現が同じであり、これによりいくつかの便利なクロスオーバーケースが可能になるという理由だけで、それらは実際には同じものではありません。

さらに、'\0'(すべての文字リテラルと同様に)は整数定数で、この場合は値がゼロです。つまり'\0'、装飾されていない0整数定数と完全に同等です。唯一の違いは、それが人間の読者に伝える意図です(「これを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
いいえ、all-bits-zeroと比較ptrすることはできません。これはではありませんが、組み込み演算子を使用した比較です。一方はnullポインター定数で、もう一方はポインターです。およびの他の2つのバージョンと同様に。これら3つは同じことを行います。memcmp'\0'NULL0
ヨハネスシャウブ-litb 2009

6
組み込みの比較演算子をビット文字列を比較するものとして使用しています。しかし、それはそうではありません。これは、抽象的な概念である2つの値を比較します。内部的に表現されていることをヌルポインタだから、0xDEADBEEFまだヌルポインタ、そのビット列ルックスが好きなものがない問題であり、それはまだに等しいとなりNULL0\0および他のすべてのヌルポインタ定数のフォーム。
ヨハネスシャウブ-litb 2009

2
あなたは比較演算子について良い点を作ります。C99をブラッシュアップしました。「値が0の整数定数式、またはvoid *型にキャストされた式は、nullポインター定数と呼ばれます。」また、文字リテラルは整数定数式であるとも言います。したがって、推移的なプロパティによってあなたは正しいですptr == '\0'
Andrew Keeton、

2
「.... NULLを#undefして奇抜なものに再定義することは可能かもしれません。これを行う人は誰でも撃たれるに値します。」これは私の良い先生が私に大声で笑わせました...
oggiemc 14

34

NULL、 '\ 0'、0の違いが何であるかを多くの人が誤解しているようです。だから、説明するために、そして前に言った事の繰り返しを避けるために:

int値0のtypeの定数式、またはtypeにキャストされたこの型の式void *は、nullポインター定数です。これは、ポインターに変換されると、nullポインターになります。標準では、オブジェクトまたは関数へのポインタ等しくないことが比較で保証されています

NULLnullポインタ定数として定義されたマクロです。

\0文字列を終了するために使用されるnull文字を表すために使用される構造です。

ヌル文字が 0に設定されたすべてのビットを有するバイトです。


14

3つすべてが異なるコンテキストでのゼロの意味を定義します。

  • ポインターコンテキスト-NULLが使用され、ポインターの値が0であることを意味します。32ビットであるか64ビットであるかは関係ありません(1つのケースで4バイト、他の8バイトでゼロ)。
  • 文字列コンテキスト-数字のゼロを表す文字の16進値は0x30ですが、NUL文字の16進値は0x00(文字列の終了に使用されます)です。

メモリを見ると、これらの3つは常に異なります。

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

これで明らかになることを願っています。


8
Nasko:評価sizeof('\0')して驚いてください。
caf

3
@Nasko:私は本当に驚いた:Cでのgccの場合:sizeof( '\ 0')== sizeof( 'a')== 4、C ++でのg ++​​の場合:sizeof( '\ 0')== sizeof ( 'a')== 1
デビッド・ロドリゲス-ドリベス

1
@Nasko:C標準(draft、n1124)から: '整数文字定数の型はint'です。したがって、 '\ 0'は実際にはCではint型なので、私のアーキテクチャではsizeof( '\ 0')は4です。 (linux、32bit)
デビッド・ロドリゲス-ドリベス

@dribeas-文字列の一部として表示されるものではなく、定数として説明していませんでした。私は間違いなくそれを明示的にすることができたでしょう。ありがとう
Nasko

@DavidRodríguez-dribeasUndid edit "Corrected '0' ASCII value to 0x20(dec 32)"
chux-Reinstate Monica

6

NULLと0がnullポインター定数として同等である場合、どちらを使用すればよいですか?C FAQリストのこの問題にも対処しています。

Cプログラマーは、ポインターコンテキストで交換可能であること、およびキャスト解除 が完全に許容されることNULLを理解する必要が あり0ます0。(とは対照的に0)NULLを使用する場合は、ポインタが関係していることを穏やかに思い出させるものと見なしてください。プログラマーは、ポインターと0整数を区別するために(自身の理解またはコンパイラーのどちらかで)それに依存すべきではありません 0

同等NULLであるの0は、ポインターコンテキストのみ です。NULL別の種類0が必要な場合は機能しますが、使用すると間違ったスタイルのメッセージが送信されるため、使用しないでください。(さらに、ANSIはの定義を許可NULLするため ((void *)0)、ポインター以外のコンテキストではまったく機能しません。)特に、NULLASCIIヌル文字(NUL)が必要な場合は使用しないでください。独自の定義を提供する

#define NUL '\0'

あなたがしなければならない場合。


5

NULL、 '\ 0'、0の違いは何ですか

「ヌル文字(NUL)」は除外するのが最も簡単です。 '\0'文字リテラルです。Cでは、として実装されているintため、0と同じですINT_TYPE_SIZE。C ++では、文字リテラルcharは1バイトのとして実装されます。これは通常、NULLまたはとは異なり0ます。

次に、NULL変数がアドレス空間を指さないことを指定するポインター値です。これは通常ゼロとして実装されるという事実は別として、アーキテクチャーの完全なアドレス空間を表現できなければなりません。したがって、32ビットアーキテクチャではNULLは(おそらく)4バイトであり、64ビットアーキテクチャでは8バイトです。これはCの実装次第です。

最後に、リテラル0は型でint、サイズはINT_TYPE_SIZEです。のデフォルト値はINT_TYPE_SIZE、アーキテクチャによって異なる場合があります。

アップルは書きました:

Mac OS Xで使用される64ビットデータモデルは「LP64」と呼ばれます。これは、SunおよびSGIの他の64ビットUNIXシステム、および64ビットLinuxで使用される一般的なデータモデルです。LP64データモデルは、プリミティブ型を次のように定義します。

  • intは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
いいえ、'\0'ありません 1バイトの値。これは文字定数であり、整数定数式です。つまり、サイズがあると言えば、サイズint(少なくとも2バイトでなければなりません)です。私を信じていない場合は、評価sizeof('\0')して自分の目で確かめてください。 '\0'0および0x0すべて完全に同等です。
カフェ、

@caf言語によって異なります。私を信じないならsizeof('\0')、C ++コンパイラを試してください。
ユージーン横田

2
sizeof(something)を印刷する場合は「%zu」を使用する必要があります
未使用


4

Cから始めるときに役立つ1つの優れた作品(LindenによるExpert Cプログラミングから引用)

1つの「l」ヌルと2つの「l」ヌル

この小さな韻を覚えて、ポインタとASCIIゼロの正しい用語を思い出してください。

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. 

ゼロのビットパターンを持つASCII文字は「NUL」と呼ばれます。ポインターがどこも指さないことを意味する特別なポインター値は「NULL」です。2つの用語の意味は交換できません。


はるかに簡単:NULなどの制御コードでありBELVTHTSOT等したがって、最大を有しています。3文字。
glglgl 2014年

2

「NUL」は0ではありませんが、ASCII NUL文字を指します。少なくとも、それは私がそれが使用されるのを見た方法です。多くの場合、nullポインターは0として定義されますが、これは実行している環境、および使用しているオペレーティングシステムや言語の仕様によって異なります。

ANSI Cでは、nullポインタは整数値0として指定されています。そのため、それが当てはまらない世界はANSI Cに準拠していません。


1

値のバイト0x00は、ASCIIテーブルでは、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
OPは '0'(ゼロ文字)ではなく '\ 0'(NUL文字)について尋ねていました
Chris Lutz

2
@Chris: '\ 0'はNULLではなく、文字リテラルで8進数にエンコードされたバイト0です。
ジョンミリキン、

2
C ++では、標準により、整数値0からポインターへの変換で常にnullポインターが生成されることが保証されています。C ++では、0はnullポインターであることが保証されていますが、NULLはマクロであり、悪意のあるコーダーがそれを別のものとして再定義する可能性があります。
デビッドロドリゲス-ドリベス

6
そして、0、NULLはすべてゼロであることが保証されていないNULLポインタのビットパターンは0であることが保証されますが、NULL定数であり、常になります
jalf

2
最初の文が間違っています-C ++では、(Cとは異なり)void *から別のポインターへの暗黙的な変換がないため、NULLを(void *)0として定義できません。

-2

(void *)0はNULLで、 '\ 0'は文字列の終わりを表します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.