• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:値のコピーについて)

値のコピーについて

このQ&Aのポイント
  • 32bitのunsigned long型の変数に、8bitのunsigned char型の配列をコピーする際に、memcpyとビット演算を使用した方法の違いについて教えてください。
  • 32bitのunsigned long型の変数に、8bitのunsigned char型の配列をコピーする際に、memcpyとビット演算を使用した方法を比較してください。結果に違いがある理由を教えてください。
  • 32bitのunsigned long型の変数に、8bitのunsigned char型の配列をコピーする際に、memcpyとビット演算を使用した方法の違いについて教えてください。また、使用する環境についても教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

この問題は、本質的には、プロセッサが扱う基本データと、物理的なメモリのデータサイズが異なることから発生しています。 つまり、プロセッサが、通常、32bit の int としてして扱うときには、プロセッサ内部では、32bit のレジスタに保持されます。ところが、これをメモリとやりとりする際、メモリの方は、8bit 区切りとしてデータを扱っています。このために、32bit レジスタ1個に入っているデータをメモリに保存する(または、この逆)の場合、メモリ中の4個の領域を使う必要があります。このときに、「メモリの中の4個の領域」をどのような順番で使うかが、エンディアンの問題です。 つまり、プロセッサがデータをメモリにどう配置するかということです。 ※もっと言えば、int は、メモリの複数領域に存在するわけですが、int という変数の「アドレス」として、どの番地 ― 最上位桁が入っているところなのか、最下位桁が入っているところなのか ― の違いです。 一方で、CやC++ の配列は、先頭の要素から、順番にメモリ上に配置されることになっています。 ※この場合、配列のアドレスとしては、「先頭の要素が存在するメモリのドレス」になります。これは、エンディアンと関係なく同じです。 これに対して、memcopy() は、文字通り、メモリの配置を換えずにそのままコピーします。ですから、数値データの配置順序と、配列の配置順序が一致しているか異なっているかで、結果が違ったり同じだったりします。 配置のタイミングとしては以下の見解であってますでしょうか? ですから、 (1)アドレスを伴った間接代入時には、配置は行われない(memcpy) これは、アドレスを伴っているからではなく、memcpy() という、配置を換えずにコピーする関数を使っているから、配置がそのままでコピーされるわけです。 (2)直接代入時に配置換えが行われる。(xxx=zzz) こちらは、少し違います。 プロセッサから見れば、配置の入れ替えは発生していません。 char bbb[4] が、 bbb[0] = 0x12; bbb[1] = 0x34; bbb[2] = 0x56; bbb[3] = 0x78; であれば、bbb[0] と同じ番地から始まる4バイトを、「int として解釈すれば」 0x78563412 となるということです。 これを、0x12345678 という数値にしようとしているわけですから、この結果を、メモリに保存したときに、結果として配置が換わってしまうことになります。 ですから、あえて言えば、プロセッサのレジスタとメモリのやりとりの際の順番がそう決まっているのだということです。 > あと、こういったコピーを行う場合は、どちらが定石なのでしょうか? (memcpyするのはありえない気がしてきました。) これも、どういうデータを使うのか。例えば、bbb[0]は、下位桁なのか上位桁側なのかによって変わってきます。 配置が矛盾しなければ、memcpy() でいっこうにかまわないわけです。 (例えば、マッキントッシュに使われていたような、Power PC では、このケースでは、配置が同じです) 逆に配置が矛盾していれば、(シフトとマスクを使うかどうかは別としても)ご質問にあったような計算をして、データの並び(というか、バイト列の並び)を変更する必要があるわけです。 最近は、ネットワークやデータベース関連でバイナリデータを使う場合にこの問題が表面化します。特に、ネットワークではデータはバイトの列で流れてくるわけですが、相手のプロセッサは特定できませんから、いずれかのエンディアンで流す必要があります。そして、ネットワークに限らずストリームデータとしては、ビッグエンディアン(上記で言えば、Power PC の流儀)のほうが自然です。そのようなわけで、Pentium などでは、バイナリデータとして流れているものを、再構成しなければならないケースが、ままあると言うことです。

その他の回答 (3)

  • nerosuke
  • ベストアンサー率33% (39/115)
回答No.4

この質問で、わざわざ環境として、CPUあたりを記述しているのは バイトオーダーだと感づいていたからだと思いますので、 参考URLをどうぞ。 http://www.atmarkit.co.jp/icd/root/70/5784470.html http://www.atmarkit.co.jp/icd/root/72/116970472.html

回答No.2

それは、「エンディアン」というものの問題です。 32bit の int aaa = 0x12345678; に対して、&aaa = 0x1000 だとすると、 0x1000 : 0x12 0x1001 : 0x34 0x1002 : 0x56 0x1003 : 0x78 と配置するプロセッサと、 0x1000 : 0x78 0x1001 : 0x56 0x1002 : 0x34 0x1003 : 0x12 と配置するプロセッサがあります。 Pentium は、後者です。 一見、前者の方が自然な表現に感じられますが、後者の方は、例えば、 union { int intValue; shot shorValue; } のようなものに対して、最下位の部分がそろうので、 intValue = 1 の時に、shotValue == 1 となるように、 同じアドレスから始まる整数データが、データ長の短い型の範囲で一致するので、都合がよいのです。 一方、char bbb[4]は、先頭番地が 0x2000 だとすると 0x2000 : bbb[0] 0x2001 : bbb[1] 0x2002 : bbb[2] 0x2003 : bbb[3] と配置されます。memcopy は、これをこのままの配置でコピーします。 シフトを伴った方法では、aaa の値が、bbb[0] * 0x1000000 + bbb[1] * 0x10000 + bbb[2] * 0x100 + bbb[3] になりますから、これを、上述のいずれかの配置で配置します。 このため、Pentium 系列のプロセッサでは、メモリ上の配置が異なることになります。 あと、ご質問とは全く関係ないことですが、「お世話様です」という表現は、目上から目下に使うというニュアンスが感じられることがあります。 この言葉は、こういった場所ではあまり適切ではないと感じられます。

参考URL:
http://ja.wikipedia.org/wiki/エンディアン
SafeGuard
質問者

お礼

回答ありがとうございます。 より理解を深めるために教えていただきたいのですが…。 配置のタイミングとしては以下の見解であってますでしょうか? (1)アドレスを伴った間接代入時には、配置は行われない(memcpy) (2)直接代入時に配置換えが行われる。(xxx=zzz) あと、こういったコピーを行う場合は、どちらが定石なのでしょうか? (memcpyするのはありえない気がしてきました。) わかる範囲で結構です。よろしくお願いします。

noname#39970
noname#39970
回答No.1

各 ccc = の所と aaa |= の所で内容を一々確認すると 理解しやすくなるからやってごらん

関連するQ&A