お世話様です。
unsigned long aaa(32bit)にunsigned char bbb[4](8bit*4)を
コピーする場合に、(1)と(2)で結果が違うのはなぜでしょうか?
よろしくご教授お願いいたします。
(1)memcpy(&aaa bbb, 4);
(2)
{
aaa = 0;
unsigned long ccc = 0;
ccc = static_cast<unsigned long>bbb[0];
aaa |= ((ccc << 24) & 0xFF000000);
ccc = static_cast<unsigned long>bbb[1];
aaa |= ((ccc << 16) & 0x00FF0000);
ccc = static_cast<unsigned long>bbb[2];
aaa |= ((ccc << 8) & 0x0000FF00);
ccc = static_cast<unsigned long>bbb[3];
aaa |= ((ccc << 0) & 0x000000FF);
}
【環境】CPU:Pentimum4 OS:WindowsXP コンパイラ:VC++8.0
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 などでは、バイナリデータとして流れているものを、再構成しなければならないケースが、ままあると言うことです。
No.4
- 回答日時:
この質問で、わざわざ環境として、CPUあたりを記述しているのは
バイトオーダーだと感づいていたからだと思いますので、
参考URLをどうぞ。
http://www.atmarkit.co.jp/icd/root/70/5784470.html
http://www.atmarkit.co.jp/icd/root/72/116970472. …
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/エンディアン
回答ありがとうございます。
より理解を深めるために教えていただきたいのですが…。
配置のタイミングとしては以下の見解であってますでしょうか?
(1)アドレスを伴った間接代入時には、配置は行われない(memcpy)
(2)直接代入時に配置換えが行われる。(xxx=zzz)
あと、こういったコピーを行う場合は、どちらが定石なのでしょうか?
(memcpyするのはありえない気がしてきました。)
わかる範囲で結構です。よろしくお願いします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Excel(エクセル) ¥マークを含むパスの処理について(マクロ、または関数) 2 2022/12/25 02:11
- SQL Server ACCESSで3ファイルを結合して、表を作成するやり方を教えて下さい。 17 2022/08/15 20:34
- Perl perl このテキストファイルを簡単に配列に入れるには? 2 2022/04/27 20:24
- SQL Server ACCESSで複数テーブルを結合して、リストを作る方法を教えてください。 2 2022/08/12 19:32
- SQL Server ACCESSで表が作りたく、そのためのSQL文や設定方法を教えてください。 1 2022/08/15 12:28
- その他(データベース) カラム上の重複を削除するクエリを教えてください 3 2022/04/12 14:11
- JavaScript JavaScript|特定URLだった時、特定の要素を変更するコードの書き方を教えてほしいです 2 2023/08/25 21:43
- その他(Microsoft Office) パワークエリの複数ファイルのデータ統合について 3 2022/07/14 17:06
- Visual Basic(VBA) 【VBA】特定の文字で改行(次の行)に行きたい。 3 2022/04/11 17:20
- Windows 10 バッチファイルの記述法とルールについてアドバイスをお願いいたします。 1 2022/04/13 10:50
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VBAの配列サイズとメモリに関して
-
C言語で、メモリを解放しないで...
-
メモリのセグメント違反の解決...
-
LoadLibraryしたらFreeLibrary
-
メモリの解放について VB6 VBA
-
C言語における再帰呼び出しの...
-
メモリ不足
-
動的メモリとexit(C言語)
-
【C言語】再帰が時間がかかる...
-
C#のOutOfMemoryException発生...
-
ファイルマッピング関数で失敗
-
メモリアロケーション異常の発...
-
再帰関数について
-
Bitmapを重ね合わせる方法
-
EXCEL-VBAにてADOのレコードセ...
-
プログラムの最大メモリ消費量...
-
緯度、経度の 10進法と 60進法...
-
Macターミナルで実行中のプログ...
-
スレッドの安全な終了のさせ方
-
バックグラウンドのプロセスの...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語で、メモリを解放しないで...
-
VBAの配列サイズとメモリに関して
-
「ヒープサイズの設定」て何?
-
C言語における再帰呼び出しの...
-
エクセルVBA 大容量CSVファイル...
-
動的メモリとexit(C言語)
-
エクセルのメモリ使用状況/Appl...
-
メモリが不足しています(VBA)
-
ファイルマッピング関数で失敗
-
大容量のメモリ確保をスワップ...
-
メモリのセグメント違反の解決...
-
メモリ不足
-
EXCEL-VBAにてADOのレコードセ...
-
エクセル キャッシュメモリー...
-
【C言語】再帰が時間がかかる...
-
C#のOutOfMemoryException発生...
-
メモリの解放について VB6 VBA
-
バッチファイルでの実行EXEのメ...
-
closeとメモリの開放について
-
「memcpy」と「strcpy」について
おすすめ情報