
No.11ベストアンサー
- 回答日時:
#4です。
C++で考えられる唯一の例外は可変引数の関数を呼び出すときです。この場合、"0"をintの0として扱うべきかdoubleの0.0として扱うべきか無効ポインターとして扱うべきか、コンパイラーが判断できない為、明示的にキャストして型を教える必要があります。この場合、単に0と書くよりはNULLの方が少しマシといった程度で、移殖性を考えると危険であることに変わりはありません。
#8他について、無効ポインターの値(ビットパターン)は処理系定義ですが、上に示した特殊な状況を除き、無効ポインターの値が何であろうとコンパイラーが定数0を無効ポインターに変換してくれます。ちなみに、mallocが失敗したときの値は、厳密にいうとNULLではなくて無効ポインター(a null pointer)です。
#10について、この場合、0と書いてもNULLと書いても同じです。"C *c = (C *)0;"の時点でcの値は無効ポインターになります。そして、無効ポインターを他の型のポインターにキャストすると必ず無効ポインターになります。
No.10
- 回答日時:
自信ないですが、C++でキャストした0は危険だと思います。
無効なポインタの"値"が0でない場合に、
struct A { ... };
struct B { ... };
struct C: A, B { ... };
C *c = (C *)0;
B *b = c;
の b が無効なポインタになるのでしょうか?
(C *)0 は定"整"数の0ではないので、無効なポインタには変換されないと思います。
素朴に考えると最後の行は
B *b = (c == (無効なC *) ? (無効なB *) : (B *)((char *)c + sizeof(A));
と同じコトになる気がします。
今、(無効なC *) != (C *)0 なので
b == (B *)sizeof(A)
になりませんか?
No.9
- 回答日時:
no.5 jmh です。
g++ には、__null というキーワードがあって、
int n = NULL; // #define NULL __null
には警告できるみたいです。でも、より明らかに間違えた感じの
int *n = 1 + 2 - 3; // == 0
は素通りみたいです。
No.8
- 回答日時:
自分で読み返して「何を言ってるのかよくわからないかも?」と感じたので、もう一度。
・インターフェース上NULLと記述することを要求している部分に関しては素直にNULLを使うべき
malloc()など「失敗したときにはNULLが返される」というインターフェースの場合、わざわざ0と比較するよりもNULLで比較するべきです。
16bit版のMS-CやVC++では0は16bitなのvoid far *malloc()の戻り値(32bitアドレス値)と比較することは推奨されません。
この場合は#define NULL 0Lと定義されたNULLと比較するべきです。
・0が(char *)0や(void *)0と同じ形式である保証はない
アドレス値のフォーマットは処理系依存です。
NULLは「インターフェース上NULLが使われることが明らかな場合」に使うべきで、「NULL」と「正しくキャストされた0」を便宜使い分けるべきです。
と、言いたかったわけです。
可読性/移植性の問題からキャストを伴わない0をアドレス値として利用することは勧められません。
この回答への補足
toysmithさん、今晩は。それから他の方にも纏めて
返信です。
まず、大前提はタイトルにも有りますように、C++
です。私はC固有の話は詳しくありません。
質問の趣旨は可読性以外にNULLを使う必要性があるか?ということですがどうやら無いようですね。この点に関しては了解しました。ということで可読性の件は終わりにします。
派生事項として、NULLと移植性との関係ですが、ヘッダーファイルを見ましたがVCではNULLは0と
定義されていました。従って、NULLでも0でも処理的には同じであるということが分かりました。
>NULLは「インターフェース上NULLが使われることが明らかな場合」に使うべきで、
>「NULL」と「正しくキャストされた0」を便宜使い分けるべきです。
#4の追伸のように単独の0をポインター値として使う場合、コンパイラーにより適切に変換される。従って、0を
キャストする必要が無いと取ったのですがこの理解は間違っているのでしょうか。
No.7
- 回答日時:
ヌルポインタをNULLと表現するのは、やはり可読性の為だと思います。
graphaffine さんが、変数名に対しては可読性を向上させる手法を認めているにもかかわらず、定数に対して窮屈な考え方をするのは、客観的にみて不自然です。
#define、const int、enum などで定義された名前のうち、0と同じものをわざわざ定義する必要はないと言っているように思えます。
0は式において「偽」であり、特別だと言えますが、NULLを0の中でもさらに特別なものと位置づけるコーディングスタイルだという事です。
No.6
- 回答日時:
まず理解しなくてはいけないのは「C,C++には組み込み定数が存在せず、NULLはプリプロセッサシンボルでしかない」ということです。
プリプロセッサがプリプロセッサシンボルを値に変換するときに文法を意識することを期待できません。
ANSI以前のCではNULL=0というのはUNIXにおける慣例にすぎず、NULLで示される無効ポインタは0という保証はありませんでした。
またint16ビット、アドレス32bitのコンパイラではNULLは0Lである必要がありました。
移植性の観点から無効ポインタを0と記述することは問題がありました。
しかし、32bitアドレスと16ビットアドレスを使い分ける必要のある場合などは「何が何でも向こうポインタはNULL」と考えると問題が発生する場合があります。
C/C++ではアドレス値の形式は処理系依存なので(char *)0とか(long *)0のように明示的なキャストを伴う値を使った方が移植性は向上します。
No.4
- 回答日時:
C++でNULLと書くのは昔のCの名残だと思います。
プロトタイプ宣言をせずに関数を呼ぶとき、コンパイラーが引数の型を知らないので、整数0なのかポインターNULLなのか、教えてあげる必要があります。C++では可変引数の関数を呼ぶ場合ぐらいにしか意味がありません。(整数とポインターの取り扱いが異なるCPUを使う場合)但し、本気で移殖性を考えるとNULLは中途半端です。神経質に考えるとintへのポインターのNULLとcharへのポインターのNULLは取り扱いが違う可能性がある為、万全を期すには個別にキャストを付けるしかないようです。
追伸:プロトタイプ宣言がある場合は、仮にNULLポインタの値が物理的に0以外の特殊な値であっても、コンパイラが0をNULLに自動的に変換してくれます。これは保証されています。
この回答への補足
furlongさん解答有り難う御座います。
>C++でNULLと書くのは昔のCの名残だと思います。
ということは、現在は実質的な意味は無いということですね。C++はプロトタイプ宣言が必須ですからね。
あと、移植性を考えた場合は0を指定した方が良いということですね。

No.2
- 回答日時:
NULLの値は0であるけれど、0はNULLと等しいのでしょうか。
ある日突然、あるいは環境によってNULLの定義が変わってしまったらどうするのでしょう。
また、ソースの品質と言うことを考えてください。
多人数でプロジェクトを組んだとき、あるいは何らかの形でソースを公開したとき、他人はあなたのコードを見てどれだけ理解できるのでしょうか。場合によっては誰かに引き継がなくてはならないこともあるでしょう。マジックナンバーだらけのコードの可読性は低く、その結果品質は低下します。適切にNULLとしておけば、引き継いだ相手を「この0の意味はなんだろう」と悩ませることもないでしょう。
個人で完結するものならどんなコーディングスタイルでも構わないでしょうけど。
この回答への補足
前半については#4追伸を御参照下さい。
また、後半は0は特別であり一般的なマジックナンバーと
同列には扱えないと思っています。
実際一般的な場合は変更があり得ますが、0は変更の必要はありませんし。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- PostgreSQL DBFluteについて質問です。 環境:PostgreSQL java8 前提:webアプリケーショ 1 2022/07/07 00:49
- PHP isset — 変数が宣言されていること、そして null とは異なることを検査 1 2022/03/27 17:34
- MySQL PHPとMySQLを使った掲示板の作り方 1 2022/06/02 13:00
- PHP PHPでCSVを出力するさいに、ループの中で前の行の値を変更したい 3 2022/10/27 17:44
- その他(コンピューター・テクノロジー) 【Tableau Desktop】文字列から8桁の数字を日付型(yyyyMMdd)として取得 1 2023/07/31 10:17
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- PHP 空文字 "" ですが 空文字の意味を教えてください。 3 2022/08/05 03:51
- C言語・C++・C# C++の標準入力の書き方 6 2023/02/23 23:53
- オープンソース Try Kotlinで readLine()を使うには 1 2023/03/27 21:06
- 大学・短大 C言語線形リストの問題です 3 2022/12/22 00:45
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
セグメントエラー
-
init関数の意味
-
戻り値で構造体を返すことは可...
-
Run-Time Check Failure #3とい...
-
C言語のポインタに直接アドレス...
-
PASCALとFARの意味
-
C言語、配列とポインタとアスタ...
-
fopne で失敗する原因
-
C言語で構造体の参照渡しができ...
-
ハンドルはポインタか
-
コーディング規約について
-
Cで作成したDLL関数をVBから呼...
-
C言語でのconstを返す関数
-
NULLとブランクの違い
-
デバイスハンドルとは?
-
CWnd::EnableWindow()の扱い方
-
アプリを32bitから64bit移行
-
NULLポインタは0と書かなければ...
-
【C言語】戻り値が構造体の関数
-
TCHAR文字列内の検索について
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語のポインタに直接アドレス...
-
fopne で失敗する原因
-
戻り値で構造体を返すことは可...
-
LPSTR型の初期化について
-
Run-Time Check Failure #3とい...
-
ExcelVBAでのkernel32(64bit)
-
参照型で受け取った引数をポイ...
-
init関数の意味
-
セグメントエラー
-
アプリを32bitから64bit移行
-
ハンドルはポインタか
-
ハンドル、アドレス、ポインタ...
-
C言語でのconstを返す関数
-
C++で関数ポインタから関数名を...
-
パスからファイル名を抽出
-
ReadFileの読み込みエラーについて
-
#define NULL ((void *)0) の弊害
-
CImage GetBitsメソッドについて
-
ポインタ変数の疑問
-
Cで作成したDLL関数をVBから呼...
おすすめ情報