Cでは、ゼロのさまざまな値(NULL
、NUL
、および0
)の間に違いがあるようです。
ASCII文字'0'
が48
または0x30
に評価されることを私は知っています。
NULL
ポインタは通常、次のように定義されています。
#define NULL 0
または
#define NULL (void *)0
さらに、NUL
という文字'\0'
があり、これも0
に評価されるようです。
これら3つの値が等しくならない場合がありますか?
これは64ビットシステムにも当てはまりますか?
注:この答えはC++ではなくC言語に適用されます。
整数定数リテラル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をチェックしてください。
NULL、 '\ 0'、および0の違いは何であるかを多くの人が誤解しているようです。それで、説明するために、そして先に述べたことを繰り返さないようにするために:
値が0のint型の定数式、またはこの型の式をvoid *型にキャストすると、nullポインタ定数に変換されます。ポインタへのポインタはnullポインタになります。標準では、任意のオブジェクトまたは関数への任意のポインタと等しくないを比較することが保証されています。
NULLは、nullポインタ定数として定義されたマクロです。 。
'\ 0'は、ヌル文字を表すために使用される構造です。文字列を終了するために使用されます。
ヌル文字は、すべてのビットが0に設定されているバイトです。
3つすべてが異なる文脈でゼロの意味を定義します。
あなたが記憶を見るとき、これらの3つは常に異なります:
NULL - 0x00000000 or 0x00000000'00000000 (32 vs 64 bit)
NUL - 0x00 or 0x0000 (ascii vs 2byte unicode)
'0' - 0x20
これが明確にしてくれることを願っています。
NULLと0がNULLポインタ定数と同等の場合、C FAQリストで? を使用する必要があります。 :
Cプログラマは
NULL
と0
はポインタの文脈では交換可能であること、そしてuncast0
は完全に受け入れ可能であることを理解しなければなりません。 (0
とは対照的に)NULLを使用する場合は、ポインタが関係していることを穏やかに思い出させてください。プログラマは、ポインタ0
を整数0
と区別するためにそれに頼るべきではありません(自分自身の理解のためにもコンパイラのためにも)。
NULL
と0
が同等であるのは、ポインタコンテキストの場合だけです。他の種類の0
が必要な場合は、NULL
を使用してはいけません。ただし、正しく機能しない可能性がありますが、間違った文体的なメッセージが送信されるためです。 (さらに、ANSIでは、NULL
の定義を((void *)0)
にすることができます。これは、ポインタ以外のコンテキストではまったく機能しません。)特に、ASCIIヌル文字(NULL
)が必要な場合は、NUL
を使用しないでください。あなた自身の定義を提供しなさい
#define NUL '\0'
あなたがしなければならない場合。
NULL、 '\ 0'、0の違いは何ですか
「ヌル文字(NUL)」を除外するのが最も簡単です。 '\0'
は文字リテラルです。 Cでは、それはint
として実装されているので、それはINT_TYPE_SIZE
の0と同じです。 C++では、文字リテラルは1バイトのchar
として実装されています。これは通常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データモデルは、次のようにプリミティブ型を定義します。
- 整数は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を返します。
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つの用語は意味において交換可能ではない。
"NUL"は0ではなく、ASCII NUL文字を表します。少なくとも、それが私がそれを使ったのを見た方法です。 NULLポインタはしばしば0として定義されますが、これはあなたが走っている環境、そしてあなたが使っているオペレーティングシステムや言語の仕様によって異なります。
ANSI Cでは、NULLポインタは整数値0として指定されています。したがって、そうではない世界はANSI Cに準拠していません。
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
値が0x00のバイトは、ASCIIテーブルでは、 "NUL"または "NULL"と呼ばれる特殊文字です。 Cでは、ソースコードに制御文字を埋め込むべきではないので、これはCの文字列でエスケープされた0、つまり "\ 0"で表されます。
しかし、真のNULLはではない値です。それは価値の欠如です。ポインターの場合、それはポインターが指し示すものが何もないことを意味します。データベースでは、フィールドに値がないことを意味します(これは、フィールドが空白、0、またはスペースで埋められていることと同じことではありません)。
特定のシステムまたはデータベースファイル形式がNULLを表すために使用する実際の値は、必ずしも0x00ではありません。