web-dev-qa-db-ja.com

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

Cでは、ゼロのさまざまな値(NULLNUL、および0)の間に違いがあるようです。

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

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

#define NULL 0

または

#define NULL (void *)0

さらに、NULという文字'\0'があり、これも0に評価されるようです。

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

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

277
gnavi

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


NULLポインタ

整数定数リテラル0は、それが使用されているコンテキストによって意味が異なります。すべての場合において、それはまだ値0を持つ整数定数です、それは異なる方法で記述されています。

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

さらに、読みやすくするために、ヘッダーファイルstddef.hにマクロNULLが用意されています。コンパイラによっては#undef NULLを作成してそれを変なものに再定義することが可能かもしれません。

したがって、nullポインタをチェックする有効な方法は次のとおりです。

if (pointer == NULL)

NULLは、NULLポインタと比較するために定義されています。有効なNULLポインター定数である限り、NULLの実際の定義は実装定義です。

if (pointer == 0)

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

if (!pointer)

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

以下は、NULLポインタをチェックするための無効な方法です。

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

コンパイラにとって、これはNULLポインタのチェックではなく、2つの変数の等価チェックです。 mynullがコード内で変更されず、コンパイラ最適化定数が0をif文に変換する場合、これはmightで動作しますが、これは保証されず、コンパイラは少なくとも1つの診断メッセージ(警告またはエラー)を生成します。 C標準に従って)。

C言語のNULLポインタとは何ですか。基盤となるアーキテクチャには関係ありません。基礎となるアーキテクチャーでアドレス0xDEADBEEFとして定義されているヌルポインター値がある場合は、この問題を解決するのはコンパイラーの責任です。

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

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

以下は、NULLポインタをチェックするための無効な方法です。

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

これらは通常の比較としてコンパイラから見られるものです。

ヌル文字

'\0'は、ヌル文字、つまりすべてのビットがゼロに設定されている文字として定義されています。これはポインタとは関係ありません。しかし、あなたはこのコードに似た何かを見るかもしれません:

if (!*string_pointer)

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

if (*string_pointer)

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

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

さらに、'\0'は(すべての文字リテラルと同様に)整数定数で、この場合は値0です。そのため'\0'は素朴な0整数定数と完全に同等です - 唯一の違いはintentにあるということです。

参考文献

詳しくは comp.lang.c FAQの質問5. をご覧ください。 C標準については this pdf を参照してください。セクション6.3.2.3ポインタ、段落3をチェックしてください。

323
Andrew Keeton

NULL、 '\ 0'、および0の違いは何であるかを多くの人が誤解しているようです。それで、説明するために、そして先に述べたことを繰り返さないようにするために:

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

NULLは、nullポインタ定数として定義されたマクロです。 。

'\ 0'は、ヌル文字を表すために使用される構造です。文字列を終了するために使用されます。

ヌル文字は、すべてのビットが0に設定されているバイトです。

32
amaterasu

3つすべてが異なる文脈でゼロの意味を定義します。

  • ポインターコンテキスト - NULLが使用され、32ビットであるか64ビットであるかに関係なく、ポインターの値が0であることを意味します(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

これが明確にしてくれることを願っています。

14
Nasko

NULLと0がNULLポインタ定数と同等の場合、C FAQリストで? を使用する必要があります。 :

CプログラマはNULL0はポインタの文脈では交換可能であること、そしてuncast 0は完全に受け入れ可能であることを理解しなければなりません。 (0とは対照的に)NULLを使用する場合は、ポインタが関係していることを穏やかに思い出させてください。プログラマは、ポインタ0を整数0と区別するためにそれに頼るべきではありません(自分自身の理解のためにもコンパイラのためにも)。

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

#define NUL '\0'

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

6
Sinan Ünür

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

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

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

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

アップルは書いた:

Mac OS Xで使用される64ビットデータモデルは "LP64"として知られています。これは、SunおよびSGIの他の64ビットUNIXシステムと64ビットLinuxで使用される共通のデータモデルです。 LP64データモデルは、次のようにプリミティブ型を定義します。

  • 整数は32ビット
  • longは64ビット
  • long-longも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を返します。

5
Eugene Yokota

1-L NUL、それは文字列を終了します。

2-L NULLは意味がありません。

そして私は黄金の雄牛を賭けるでしょう

3-L NULLLがないこと。

あなたはどのようにNULに対処しますか?

4
EvilTeach

Cから始めるときに私を助ける1つの良い部分(LindenによるエキスパートCプログラミングから取られる)

One 'l' nullとTwo 'l' null

ポインタとASCII zeroの正しい用語を思い出すために、この小さな韻を覚えてください。

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つの用語は意味において交換可能ではない。

3
dlmeetei

"NUL"は0ではなく、ASCII NUL文字を表します。少なくとも、それが私がそれを使ったのを見た方法です。 NULLポインタはしばしば0として定義されますが、これはあなたが走っている環境、そしてあなたが使っているオペレーティングシステムや言語の仕様によって異なります。

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

2
peterb

NULLは0であることを保証されていません - 正確な値はアーキテクチャに依存します。ほとんどの主要なアーキテクチャはそれを(void*)0に定義しています。

'\0'は常に0になります。これは、バイト0が文字リテラルでエンコードされる方法だからです。

CコンパイラがASCIIを使う必要があるかどうか私は覚えていません - そうでなければ、'0'は必ずしも48に等しくないかもしれません。あなたが非常にあいまいなシステムに取り組んでいるのでなければ。

さまざまなタイプのサイズは64ビットシステムで異なりますが、整数値は同じになります。


NULLが0に等しいが、beゼロではないことに疑問を投げかけている人もいます。これは、そのようなシステムで予想される出力とともに、プログラム例です。

#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
0
John Millikin

値が0x00のバイトは、ASCIIテーブルでは、 "NUL"または "NULL"と呼ばれる特殊文字です。 Cでは、ソースコードに制御文字を埋め込むべきではないので、これはCの文字列でエスケープされた0、つまり "\ 0"で表されます。

しかし、真のNULLはではない値です。それは価値の欠如です。ポインターの場合、それはポインターが指し示すものが何もないことを意味します。データベースでは、フィールドに値がないことを意味します(これは、フィールドが空白、0、またはスペースで埋められていることと同じことではありません)。

特定のシステムまたはデータベースファイル形式がNULLを表すために使用する実際の値は、必ずしも0x00ではありません。

0
richardtallent