- ベストアンサー
C++で2つ質問です
C++で2つ質問です。 char str[1]; これは char str; と同じですか? memcpy(str,NULL,0); これはやってもよいと定義されていますか?
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
【char str と char str[1]】 まず、 char str; char str[1]; は、前者は char 型の単純変数。後者は、char 型の入れるなので、異なるものです。 実体としては、いずれも char 1 個分の変数領域を占めてそれ自体は(それぞれ、str と str[0]として)同様に扱えるので、その意味では同じとも言えます。 また、 char str[1]; としたときの、str は、あくまでも「配列名」です。 C言語では、「多くの文脈では、配列名は配列の先頭アドレスに暗黙のうちに変換される」ので、配列とポインタの混乱というのはおきやすいのですが、本来別のものです。 これがよくわかるのは、 char array[1]; char *pointer; という2つがあったとして、 1. sizeof array は、'1' です。 sizeof pointer は、ポインタのサイズで、おそらく、1ではありません。 2. &array は、array の先頭アドレスです (多くの文脈では、arrya を &array に書き換えても、「最終的には」同じ動作をします) &pointer は、pointer という変数自体をポイントするアドレスです。 (多くの文脈では、pointer を &pointer に書き換えると、コンパイルすら通らないでしょう) 【memcpy(str, NULL, 0)】 これは、「やってはいけない」という記述を見つけることは出来ませんでした。 しかし、こういうことを考えてみるのは、無意味ではありません。直接上記の記述をすることはないと思いますが、 memcpy(dest, src, size); と記述した中で、たまたま、dest が NULL だったとか、src が NULL だったとかという際の挙動を把握しておくのは、不具合の解析に役立ちます。 また、厳密に言えば、NULL が、「0番地」である保証はありません。(逆に、定数 0 をアドレスに変換すると、NULL になることは保証されています) あくまでも、「そのポインタは、『何もポイントしていない』ということを示す定数」です。 【エラーにならなかったので……】 コンパイラが「エラー」と表示するのは表面的なことに過ぎません。今回の例でいえば、memcpy の引数が、順に、「何かのアドレス、何かのアドレス、サイズを表す数値(size_t)」であることをチェックしているだけです。 コンパイラは、その意味までは関知しません。
その他の回答 (4)
- matsu-td
- ベストアンサー率31% (5/16)
#2です。 > 前者では、strは配列の先頭アドレスを表すポインタです。 この表現は間違いでした。AsanoNagiさんの説明が正しいです。訂正させて頂きます。
- matsu-td
- ベストアンサー率31% (5/16)
> エラーになればやっていけないことと分かりますが > エラーにならなかったので定義を知りたいです。 エラーというのはコンパイルエラーということですか? コンパイルエラーは出ないと思います。文法的に間違っていないからです。 例えば、 memcpy (NULL, str, 1); これもコンパイルエラーは出ませんが、絶対にやってはいけません。memcpyの仕様としてやってはいけないと定義されているのではなく、0番地を上書きしてしまうからやってはいけないのです。これはC/C++プログラミングでは常識ですね。繰り返しますが、「常識」であって、「仕様」または「定義」ではありません。memcpyは、与えられたパラメータで言われた通りに動くだけで、それをどう使うかはプログラマに責任があるのです。 また、inughさんの例では、実行時でも問題なく動作すると思います。なぜなら、書き込みバイト数が0バイトなので、実質的には何も行われないからです。 memcpy(str,NULL,0); は、全く意味の無いプログラムです。 memcpy()を自作してみると、分かるかもしれませんね。
お礼
ありがとうございます。 2つ目の質問の回答は、やってもよいと定義されていないが、やってはいけないという定義は見たことがない。 ということでしょうか? No.7の回答まで目を通しました。 memcpy(str,NULL,0);はやってはいけないということはなさそうですね。 エラーというのがコンパイルエラーなのか実行エラーなのかを答えても意味がありません。 それがどっちのエラーであろうとエラーが起こらなかったわけですから定義を知る必要があります。
- matsu-td
- ベストアンサー率31% (5/16)
1. char str[1]; と char str; では、strというシンボルの扱いが変わります。 前者では、strは配列の先頭アドレスを表すポインタです。後者では、char型変数の実体になります。 前者をchar型の変数として扱う場合は、str[0]としなければいけません。 以下のようなプログラムは、コンパイルできません。 char str1[1]; char str2; str1 = str2; // 型が違うので、代入できない。 2. やって良いかどうかは知りませんが、 「strの指すアドレスに、0番地(NULL)から始まるデータを0バイト分コピーする」という意味になると思いますし、プログラムはその通り動くと思います。 結果どうなるかは、実際に試してみるのが一番良いと思います。
お礼
ありがとうございます。 1は分かりました。 2はエラーになればやっていけないことと分かりますがエラーにならなかったので定義を知りたいです。
- xcrOSgS2wY
- ベストアンサー率50% (1006/1985)
(1) char str[1]; と char str; は違います。 (2) 「やってはならぬ」とは定義されていません。
お礼
ありがとうございました。