- ベストアンサー
NULLポインタは0と書かなければだめ?
C++言語を使っています。 C++言語でNULLポインタを表す場合、0やNULLを使用しますが、 「NULLは単なるマクロなので本来は0を使わなければだめ」という話を聞きました。 つまり、 int *p = 0; が本当の正しいNULLポインタであり、 int *p = NULL; は推奨されていない(?)NULLポインタというようです。 今まであまり疑うことなく、NULLポインタを表すのにNULLを使用していましたが、 上記の内容は本当でしょうか。
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
(1) NULL を使った方が良いという意見と 0 を使った方が良いという意見の両方がある 規格にはどちらかを使ってはいけないなどという記述はありません。また、C++ では NULL は #define NULL 0 とされるので、実質的にはどちらも同じです。従って、どちらかが推奨されるとしたら、可読性やミスを減らすという観点から議論される事になると思います。因みに、No.3 の #define NULL ((void*)0) は C 言語の場合です。 先ず、NULL を使うと「意味的にそれがポインタを意図している」という事がプログラムの読み手に伝わりやすく、良いとする人があります。(これが、そもそもマクロとして NULL を定義した切っ掛けだと思います。) しかし、問題点は NULL は単なる 0 に展開されるので、それが「ポインタを意図した 0 である」という事がコンパイラに伝わらないという所にあります。例えば、 void f(int*); void f(int); の前者を呼び出そうと思って f(NULL); と書くと f(0); に展開され、実際には後者が呼び出されます。null ポインタを 0 と書いていれば f(0); まで書いた時点で「おや、これはまずいぞ」と気付く可能性が高いですが、NULL と書いていると認識として「NULL はポインタ」という先入観がある為に f(int*) の方が呼び出される様に錯覚してしまいます。因みに、前者の f を正しく呼び出す為には f((int*)NULL) または f((int*)0) とする必要があります (別に 0 と表記していれば何も注意が要らないという訳ではなくやはりキャスト (int*) が必要になりますが、その事に気付きやすいという事です)。 これに対して、そもそもポインタを受け取る関数と整数を受け取る関数を同名で多重定義する事自体が問題なのではないかという反論もあります。つまり、f(int*) f(int) の呼出の問題は、引数に NULL を指定した事に問題があるのではなくその様な多重定義をしてしまった事に問題があるのであって、これは NULL を敬遠する理由にはならないという主張です。 何れにしても、 > 「NULLは単なるマクロなので本来は0を使わなければだめ」 の記述は、違います。0 が推奨される理由は NULL がマクロだからだとかではありません。マクロは偽物で即値が本物なので、即値の方が良いなどという議論は成立しません。マクロの方が読みやすければ、即値ではなくマクロを使うべきです。例えば EXIT_SUCCESS, EXIT_FAILURE, SEEK_SET などのマクロ定数は使った方が分かりやすいプログラムになります。 NULL に関して賛否両論があるのは、C言語からC++への発展の際の矛盾 (ここでは説明しませんでしたが) などの複雑な背景があるからなのです。 (2) C++11 では nullptr 先に述べたように NULL と書くのも 0 と書くのも欠点があるので、それを補う為に C++ の 2011 の規格で nullptr という新しいキーワードが追加されました。今後は、C++11 に対応している新しいコンパイラでは nullptr を使っていくと良いでしょう。(勿論、古いコンパイラでコンパイルできなくなるという問題点はありますが)。 (3) null ポインタを表す整数リテラルは常に 0 です No.1 補足。 確かに NULL ポインタの「内部表現」(機械の中でどう表されるか) は処理系依存なので、null ポインタのビットパターンをそのまま整数として解釈 (reinterpret_cast) した時に 0 になるとは限りません。しかし、ソースコードの上では常に 0 と表します。なぜならば、整数を普通にポインタに変換 (static_cast) する場合は、整数の 0 と null ポインタが対応する様に変換されるという事が保証されているからです。
その他の回答 (8)
- wormhole
- ベストアンサー率28% (1626/5665)
>http://www.curiocube.com/mikata/oop/p1_ch09_nonull.php Func(0); これを後で読んだ場合、ポインタのつもりだったのか数値の0のつもりだったのかわからないと思いますが。 C++で Func(NULL) を「Func(int *)が呼び出されることを意図したコード」というのが、そもそもの間違いですし。 NULLを使うにしろ0を使うにしろFunc(int *)が呼び出されることを意図したコードは Func((int *)NULL); Func((int *)0); です。 >http://www.geocities.jp/bleis_tift/cpp/null.html NULLの定義は確かに処理系依存ですがNULLポインタの内部表現自体処理系依存です。 NULLが思った通りの動作をしない事があるというのもNULLの使い方を間違えてるくらいしか私には思いつかないです。 3番目については「NULLは単なるマクロなので本来は0を使わなければだめ」といった内容には思えないですけど。
お礼
3つ目の参考URLについて、 「@5mingame2 @torotiti 「NULL」はあくまでもC言語用マクロであって、C++では「0」と比較するのが正しいと教わりましたが、(以下略」 とか 「@5mingame2 逆だと思いますよ。ポインタに参照無しは0と書くのが本来で、NULLは単なるマクロです。」 とかあったので、そういう話だと思いました。
- mk48a
- ベストアンサー率56% (1133/2007)
補足です。 Microsoftのフォーラムのリンクです。 http://social.msdn.microsoft.com/Forums/ja-JP/8096f9d1-a4a7-44a8-8baf-476aa4868fab/0null?forum=vcgeneralja EffectiveC++からの引用があります。 要は0でも弊害が出るのでnullptrを使うべきだが、使えない環境もある。 ソースから検索して置換する場合0だと難しいが、NULLだとやり易い。 という感じかと。 http://msdn.microsoft.com/ja-jp/library/vstudio/4ex65770%28v=vs.110%29.aspx
お礼
回答ありがとうございます。 > ソースから検索して置換する場合0だと難しいが、NULLだとやり易い。 そういえば、そうですね。 NULL にしておくと、後のメンテナンスがしやすいのかもしれません。
- akinomyoga
- ベストアンサー率85% (100/117)
#6 の方へ 申し訳御座いません。原稿を書き終わった後に改めて回答がついていないかを見たのですが、適当に見てしまったせいで見落としておりました。
お礼
解決しました。 ありがとうございます。
- wormhole
- ベストアンサー率28% (1626/5665)
#4の方へ >因みに、No.3 の #define NULL ((void*)0) は C 言語の場合です。 #3では「C言語だと」と前置きしていますが。 C言語でも、そういう話はないですということ書きたかったわけなんだけど。
お礼
理解しております。
- mk48a
- ベストアンサー率56% (1133/2007)
>「NULLは単なるマクロなので本来は0を使わなければだめ」という話を聞きました。 その発想であれば、マクロは全部使うなということになりますが、マクロは機種やコンパイラ依存の部分を吸収する目的もあるので、その主張には無理があるかと思います。 一応現在は言語使用上NULLポインタは0となっているので、0を使用するのは間違いではありませんが。 参考 http://www7b.biglobe.ne.jp/~robe/cpphtml/html01/cpp01063.html 現在は可読性を重視するプログラムが主流なので、どちらが読みやすいかですが、個人的にはNULLの方が意味をとらえやすいと思います。 0だと数値と間違えやすい。 その話をした人に何でマクロを使用してはいけないのか聞いて見ましょう。
お礼
回答ありがとうございます。 No.4の回答で理解できました。
- wormhole
- ベストアンサー率28% (1626/5665)
その話が本当という事になるとC言語でも 「NULLは単なるマクロなので本来は((void*)0)を使わなければだめ」 という事になりますけど。 それにそれだとNULLと同様にマクロで定義された定数は、即値で書くべきという事になりそうな。
お礼
回答ありがとうございます。 No.4 の回答で理解できました。
補足
No.1 の回答の補足にいくつかページのURLをつけたので、 そちらも参照していただけませんか。
- aozakana_dha
- ベストアンサー率45% (76/168)
使ったらダメということでは無いですが、話の背景は間違っていないと思います。 C言語のNULLマクロとC++のNULLマクロは全く異質の物であり C++におけるNULLマクロはただ単に0と展開されるだけのようです。 また、これは整数のゼロとNULLポインタの区別がつかないことを意味し、 場合によっては多重定義された関数が正しく選択されないという問題が発生します。 この問題を解消するため、新しい標準では NULLポインタ専用に nullptr というキーワードがあるようです。 【参考】 More C++ Idioms/nullptr http://ja.wikibooks.org/wiki/More_C%2B%2B_Idioms/nullptr C++11 https://ja.wikipedia.org/wiki/C%2B%2B11
お礼
回答ありがとうございます。 話の背景は間違っていない、というのはよくわかりませんでしたが、 全体としては、No.4の回答で理解できました。
- BuriBuri4
- ベストアンサー率28% (150/525)
そんな嘘っぱち誰に聞いたの? 処理系依存だからNULLが0じゃない場合もありますよん。
お礼
No.4の回答で理解できました。
補足
このあたりでしょうか。 http://www.curiocube.com/mikata/oop/p1_ch09_nonull.php ページ最後 「このような失敗を防ぐためには、NULL マクロを使わないことです。いままでこのマクロに親しんできた人には少し辛い別れかもしれませんが、これからは NULL と書くかわりに 0 と書きましょう。」 http://www.geocities.jp/bleis_tift/cpp/null.html ページ真ん中あたり 「NULLの代用 そもそもNULLはC言語との互換性のために残されているマクロ定義であり、 C++では不必要な存在なのです。 C++で(C言語で言う)NULLを表現したい場合、 0を使用します。 0は任意の型のヌルポインタに変換される事が保証されているので、 どんなNULLマクロよりも安全です。 」 http://togetter.com/li/110100 全体的に 3つ目のページはよくわからない記述もありますが。。。 > 処理系依存だからNULLが0じゃない場合もありますよん。 これはどういう意味(意図)か、ちょっと私にはわかりませんでした。 すいません。
お礼
回答ありがとうございます。 大変参考になりました。