エンディアンについての質問

このQ&Aのポイント
  • エンディアンについての質問です。リトルエンディアンからビッグエンディアンへの変換について教えてください。
  • エンディアンの違いについて認識していますが、32ビット以上のデータのエンディアン変換は必要ないのでしょうか?
  • リトルエンディアンとビッグエンディアンの意識すべき範囲について混乱しています。エンディアンについて教えてください。
回答を見る
  • ベストアンサー

エンディアンについて

すみません。 教えてください。 リトルエンディアンからビッグエンディアンに変換しないと いけません。 エンディアンについては勉強したつもりですが、 どうしてもわからないことがあります。 ご存知の方、教えていただせんか? CPUはリトルです。 まず、エンディアンの違いについては 以下のように認識しています。 x = 0xAABBCCDD メモリの配置方法が、 トリルだと DD CC BB AA ビックだと AA BB CC DD だと思っています。32ビットの場合です。 で、これを変換するには、htonlで変換可能だと思っっています。 (試したところ可能でした) で次に、32ビットを超えるデータ、たとえば100バイトとかを mallocにして変数に代入しました。 この時はエンディアン変換(ファイルに出力する際)は必要ないのでしょうか? 試しに出力すると、 x = 0x AA BB CC DD EE FF GG ・・・・・・ZZ (100バイトと仮定) バイナリでの出力結果は AA BB CC DD EE FF GG ・・・・・となっていました。 私の認識だと、本CPUはリトルエンディアンのため、 ZZ ・・・・・・・・ DD CC BB AA (四バイトずつ反転しているデータ) が出力されるものと思っていました。(反転してメモリに格納されるため) リトル/ビックを意識しないといけないのは、 2バイトや4バイトの時のみで、それを超える大きなデータ(100バイト)などは 意識せず、そのままバイナリ出力しても、ビックエンディアンで出力されると いうことでよろしいでしょうか? そうなると、エンディアンってなんだんだ???と混乱しています。 わかりにくい説明で大変申し訳ござませんが、 よろしくお願いいたします。

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

  • ベストアンサー
noname#140082
noname#140082
回答No.5

C言語で説明しますが、特にC言語を知らなくとも大丈夫だと思います。 まず、C言語では char 1byte整数 short 2byte整数 long 4byte整数 と決まっています。 この場合 char c = 0x12; これに関しては、ビッグエンディアンもリトルエンディアンも関係ありません。 ですから、 char cs[100]; と言うのも、同様にビッグエンディアンもリトルエンディアンも関係ありません。 たぶん、質問者さんが言われている100バイトのデータがこれに該当すると思います。 そして問題なのは、 short s = 0x1234; long l = 0x12345678; など、2バイト以上の型の並び順です。 リトルエンディアンで言えば s を1バイト単位で見た場合、c[0]=0x34,c[1]=0x12となります。 l を1バイト単位で見た場合、c[0]=0x87,c[1]=0x65,c[2]=0x43,c[3]=0x21となります。 逆にビッグエンディアンの場合は s を1バイト単位で見た場合、c[0]=0x12,c[1]=0x34となります。 l を1バイト単位で見た場合、c[0]=0x12,c[1]=0x34,c[2]=0x56,c[3]=0x78となります。 10進数で、たとえてるなら「一、十、百、千」と4桁の10進数があった場合 リトルエンディアンだと並びが、「一、十、百、千」 ビッグエンディアンだと並びが、「千、百、十、一」 になると言うもので、つまり並びの重みの向きが違うと言うものです。 アドレス(番地)は、1バイトごとに付けられます。 つまり、 char a[4];とあり、もしa[0]が0番地とした場合、 a[4]は3番地となります。 そして、4バイト整数は連続した4つの番地を使う訳ですが、この場合の0番地が大きい位なのか、小さい位なのかでビッグエンディアン/リトルエンディアンと呼ばれるようになります。 また、最近では8バイト(64bit)も普通に扱えるようになりましたが、これも考えは同じです。 そして、雑学的なことを書けば、リトルエンディアンのメリットは、たとえばlongで定義したエリアの中身が実際には0か1しか値が入らないと言うケースはしばしば発生します。 それをもし、何か間違ってcharで参照したとしても、それは正確に0か1が参照できるのです。(つまり1バイトに収まる値ならば正しく参照可能) 昔は、このようなことをメモリが少なかったため裏技的にやる人もいましたが、もちろん今ではトラブル以外の何ものでもないため、絶対にやりません。

その他の回答 (6)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.7

もはや余談の範疇ですが, 世の中には「PDP エンディアン」のような奴もいるので一筋縄ではいかなかったりします. なんか, もっと変態ちっくなやつもあるみたいだけど. で実行時に「どうしてもエンディアンを知りたい」と思ったら #include <limits.h> union FindLongEndian { unsigned long lval; unsigned char byteorder[sizeof (unsigned long)]; } x; x.lval = 0; for (unsigned int i = 1; i <= sizeof (unsigned long); ++i) { x.lval = (x.lval << CHAR_BIT) + i; } とすれば x.byteorder[] に入ってくれる... かな? ところで「char が 1バイト, short が 2バイト, long が 4バイト」に決まってる言語が想像つかないんだけど, 何かあったっけ?

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.6

私が普段使っている、MacOSX(64bitカーネル)のgccでは、sizeof(long)==8 なのですが... <「longは4バイトと決まっている」 さて。 同じmallocでも、 char *buff = malloc(100) ; short * s = (short *) buff ; として s[0]=0x1234 ; とすると、 buff[0]==0x34 ; buff[1]==0x12 ; となります(sizeof(short)==2,リトルエンディアンの場合) これがビッグエンディアンだと buff[0]==0x12 ; buff[1]==0x34 ; となります。 ・buff[0],buff[1]のchar2つが、s[0]のshort一つになる:これがcharが100個か、2個の塊(short)が50個か、ということ。 ・そのどちらに上位が入るか、がエンディアン マス目に書いてみたり、Excelみたいな表に書いてみたりすると、イメージしやすいかもしれません

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.4

あー、そういえば質問の例示だと100byte全体で反転してますねぇ>#3 後ろの文章しか読んでませんでした。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

「4Byteデータ25個のカタマリ」だとすると (4バイトごとに格納されるので) DD CC BB AA HH GG FF EE ... のような気がしますが>#2.

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.2

ケースバイケース、としか言いようがありません。 質問のケースでは、「100Byteのデータ」というのが所詮「1Byteデータ100個のカタマリ」でしかないためです。 これが「4Byteデータ25個のカタマリ」であればあなたの想定通りの結果になります。

sav_moster
質問者

補足

ご回答ありがとうございます。 Tacosanさんに追加で質問を書いて登校してから あっ思いました。結論は以下ということですよね。 間違っていたら、ご指摘ください。 ----------------- 質問のケースでは、「100Byteのデータ」というのが所詮「1Byteデータ100個のカタマリ」でしかないためです。 これが「4Byteデータ25個のカタマリ」であればあなたの想定通りの結果になります。 ----------------- なので、 long int の場合は4バイト確保されているので、 メモリ上には逆に入る。 char *buff に いくらmalloc(1000)をしたところで、 それは1バイトのデータが1000ということなので、 反転されない。(1バイトはそのままメモリに格納されるから) ということですよね? まさに、 --------------------------------- 「100Byteのデータ」というのが所詮「1Byteデータ100個のカタマリ」でしかないためです。 --------------------------------- ということですね。 少しエンディアンについて理解できた気がします。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

「htonl でビッグエンディアンに変換できる」というのは正しいといえば正しいんだけど, より正確には ホストのバイトオーダーからネットワークバイトオーダーに変換する です. もちろん「ネットワークバイトオーダー」は「ビッグエンディアン」なので, リトルエンディアンのホストで実行すれば結果的に「リトルエンディアンからビッグエンディアンに変換できる」ということにはなります. 後の例は ・「32ビットを超えるデータ、たとえば100バイトとかをmallocにして変数に代入しました。」というのがどのように入れているのかが分からん ・「バイナリでの出力」はどのようにしているのか不明 など, ここには書かれていないことがいくつかあるのでなんとも言えません. 具体的に「こんなコードでこうやったんだけど....」というのが出てくれば言いようもある.

sav_moster
質問者

補足

みなさん、ご回答ありがとうございます。 説明不足で申し訳ないです。 >・「32ビットを超えるデータ、たとえば100バイトとかをmallocにして変数に代入しました。」 >というのがどのように入れているのかが分からん ですが、 a[] = {"AA","BB","CC"・・・・・ZZ}(100バイト) char *buff; buff = malooc(100); memcoy(buff, a, 100) として代入しています。 >・「バイナリでの出力」はどのようにしているのか不明 は、 "wb" で開いたfpに、 fwrite(buff, 1, 100, fp) としています。 この時、ファイルには、 AABBCCDD・・・・・ZZと出力されています。 ZZ・・・・・BBAA とは出力されていません。 リトルエンディアンなのに、そのまま出力されている現象が 理解できていません。 ちなみに int32 a = 0xAABBCCDD; とすると、DDCCBBAAと出力されています。 以上、よろしくお願いいたします。

関連するQ&A

  • JAVAのdouble型情報をリトルエンディアンでバイナリへ出力の方法

    JAVAでdouble型の情報をリトルエンディアンでバイナリとして出力する方法を教えてください。 現在、java.io.DataOutputStreamを使用し、writeDoubleで出力していますが、ビックエンディアンとしてしか無理でした。 読み込むのはテキスト型で出力がバイナリ。 現在のソースの簡易フローチャートを書いて置きます。 START ↓ テキストファイルから特定の文字列を取得する(1 , 7 , 5.5等) ↓ 取得した文字列をそれぞれ対応の型に変換する int top = Integer.parseInt("1"); int sub = Integer.parseInt("7"); double miks = Double.parseDouble("5.5"); ↓ バイナリのフォーマットに合わせて出力する int型は4バイトでビックエンディアン。 double型は8バイトでリトルエンディアン。 例えば、デフォルトのビックエンディアンで出力した時、数字の1は 00 00 00 01 になりますが、 リトルエンディアンで出力した時は、 01 00 00 00 になると思います。 変換するタイミングとしては、書き込む時にオリジナル機能(メソッド)で書き込むデータ(int型やdouble型)とビックかリトルを指定して、バイナリに出来るものを探しています。 PS 現在の質問はソースを上げるのが一番とは思いますが、社外秘のソースなので、公開することは出来ません。 PPS 私の質問に対する質問があれば、より詳細に答えていくつもりです。 以上、宜しいお願い致します。

    • ベストアンサー
    • Java
  • エンディアンを知るには

    リトルエンディアンのマシンで作ったバイナリデータをいろいろなマシンで読み込みたいのですが、一部がビッグエンディアンなので変換の必要があります。ただ、ソースを共通にしたいのでエンディアンを知ることができるマクロの値でエンディアンの違いの処理を行いたいのですが、どのようなマクロを使えばいいのでしょうか?

  • Javaでのエンディアン変換

    こんばんは☆ Javaでのエンディアン変換をご教授ください。 ファイルを読み込み、ソケット通信でサーバへデータ送信しています。 リトルエンディアンで送らなければいけないのですが、 Javaはプラットフォーム問わずにビッグエンディアンでメモリに格納するとありました。 そこで、バイトオーダーをしようと思い、 stirlingというバイナリエディタでバイナリファイルを作成して以下の2点で試しました。 <バイナリファイル構造体> struct stest { LONG l1; LONG l2; LONG l3; LONG l4; }; <バイナリデータ(数値)> 1234 (010000020000030000040000)←バイナリエディタで見たとき <テスト1結果> ・・・new InputStreamReader(in, "UnicodeLittle"); >1000200030004000 <テスト2結果> ByteBuffer buffer = ByteBuffer.wrap(bt); buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.get(); >1000200030004000 これはリトルエンディアンなのでしょうか? どちらも、 Javaで読み込み時にエンディアン指定しない時と出力結果に違いがありませんでした。 なぜでしょうか? ちなみに、データ型を意識せずに変換したいです。 色々と調べたのですが、良く分かりません。 どなたかご教授お願いいたしますm(_ _)m

    • ベストアンサー
    • Java
  • リトルエンディアン、ビッグエンディアンについて

    リトルエンディアン、ビッグエンディアンについて 質問があります。 (1)簡単にそのPCがリトルエンディアンなのか、ビッグエンディアン  なのか、分かる方法はありますか?  簡単なCプログラムを書いてメモリ状態をダンプするのが、  一番早いのでしょうか?  それとも、Intel系?モントローラ系?CPUにはあまり詳しくないので、  分かりませんが、これらのどちらかに属していれば決められるので  しょうか?ほかの系とかあるのかな・・・ (2)ネットワークプログラミングをするときに、ビッグエンディアンの  マシンからデータを送出する場合には、htonlなどの関数を使用しなく  ても問題ありませんでしょうか?(ネットワークバイトオーダが  ビックエンディアンであるため)

  • ビックエンディアンで動作するPC

    バイトオーダでビックエンディアンとリトルエンディアンがあるのは知っていますが、 実際にビックエンディアンで動作するPCを見たことがありません。 (といいますかビックエンディアンで動作しているか分かりません) 秋葉原等でビックエンディアンで動作するPC(CPU・マザーボード)は買うことはできるのでしょうか? その場合のOS、Linuxになると思いますがディトリビューションどれがよいのでしょうか? クロスコンパイル環境に興味があり、エンディアンが違うPCでも動作するプログラムを 書いてみたいと興味があり質問させていただきました。

  • エクセルの表を回転したいのですが

    こんなことってできるのでしょうか。 1aA 2bB 3cC 4dD 5eE 6fF 7gG という風に書き込んでいる表があるのですが、これを 12345678 abcdefgh ABCDEFGH と書き直したいのです。 ご存じの方、よろしくお願い致します。

  • ビッグエンディアンをPCで処理する問題

    ビッグエンディアンと指定されているバイナリファイルがあります。 これをPC(intel系,Linux or Windows)で処理する場合、エンディアンの変換が必要だろうと思います。具体的にはどのようにするのでしょうか。ネットでもダウンロードできそうですが。 変換コマンド -btol ファイル名(ビッグ)> ファイル名(リトル) という感じですかね。こんなものあるでしょうか。 購入したバイナリファイルなのですが、このご時勢たいていPCで処理するわけでしょうからリトルであってほしいものだと思いますが。 ところでMACはビッグとリトルのどっちなのでしょうか。

  • エンディアンの問題

    バイナリファイルの記憶の仕方にビッグエンディアンとリトルエンディアンがあります。たとえば16ビットのうちの前半の8ビットと後半の8ビットが逆になっていることだと思います。そこで質問ですが、 ○なぜ、そういう風に分かれているのか。 ○この問題が顕在化するのはどのような場合か。 ○その解決方法は? という点について教えて頂きたいのですが。私の記憶では例えばUnixとDOS(Windows)で逆である(どちらがどちらなのか分かりませんが)ということでした。もし、そのことが問題であれば、解決法としてはとにかく反転すればよいということになるかもしれません。簡易ソフトなどもあるようですし、自分でプログラムを書いたこともあります。もちろんどちらが本当に正しいのか判別できなければなりませんが。

  • Excelで行を切り貼りをすると上書きされてしまうのでしょうか?

    5行ある下2行を切り取って、1行目に移動したいのですが、 AA BB CC DD EE ↓こうならず、 DD EE AA BB CC ↓こうなります。 DD EE CC 上書きされるようです。 行のコピー&ペーストは挿入されないのでしょうか?

  • JavaScriptで計算表

    下記のような計算式を作りたいのですが、ご教授願えませんでしょうか。 AA項目  セレクトボックスで、あ~おから選択(1)      セレクトボックスで、あ~おから選択(2)      セレクトボックスで、あ~おから選択(3)      セレクトボックスで、あ~おから選択(4)      セレクトボックスで、あ~おから選択(5)  ※ あ=40、い=30、う=20、え=10、お=5 とする BB項目  ユーザ入力(1)      ユーザ入力(2)      ユーザ入力(3)      ユーザ入力(4)      ユーザ入力(5) CC項目  AA項目とBB入力を掛けた計算結果表示(1)      AA項目とBB入力を掛けた計算結果表示(2)      AA項目とBB入力を掛けた計算結果表示(3)      AA項目とBB入力を掛けた計算結果表示(4)      AA項目とBB入力を掛けた計算結果表示(5) DD項目  2割~8割からセレクトボックスで選択(1)      2割~8割からセレクトボックスで選択(2)      2割~8割からセレクトボックスで選択(3)      2割~8割からセレクトボックスで選択(4)      2割~8割からセレクトボックスで選択(5) EE項目  セレクトボックスで、か~こから選択 ★ CC項目とDD項目を掛けた数字をすべて足した数字表示 「FF」   (例:CC項目(1)=DD項目(1)、CC項目(2)=DD項目(2)という考え方)   ★ CC項目とDD項目ごとに掛けた数字にEE項目で選択した数字を掛けて足した数字表示 「GG」    「計算ボタン」    「クリアボタン」 *************** 1.AA項目、BB項目は、必ずしも全部を選択しない(CC項目、DD項目も連動) 2.各項目も(1)と(1)で計算  (例)    AA項目(1)とBB項目(1)の計算結果がCC項目(1)に表示    CC項目(1)とDD項目(1)を計算 3.EE項目は、AA項目の選択の種類によって、掛ける数字が変わってくる。    AA項目 あ  EE項目 か = 20.2    AA項目 い  EE項目 か = 15.8    AA項目 う  EE項目 か = 13.7    AA項目 え  EE項目 か = 10.5    AA項目 お  EE項目 か = 8.2    AA項目 あ  EE項目 き = 31.6    AA項目 い  EE項目 き = 28.1    AA項目 う  EE項目 き = 22.4    AA項目 え  EE項目 き = 17.2    AA項目 お  EE項目 き = 14.7 4.GG項目は、CC項目とDD項目ごとに計算した数字に、3.で選択した数字を掛けて足した合計を表示   (例)     CC項目(1)とDD項目(1)を掛けた数字に、AA項目で「あ」を選択し、EE項目は「か」を選択 5.計算ボタンをクリックすると、「FF」と「GG」を計算する 6.クリアボタンをクリックすると、すべてクリアとする      ************ 仮に AA項目 「あ~う」までを選択 BB項目 (AA項目「あ」=15、AA項目「い」=8、AA項目「う」=3) DD項目 (AA項目「あ」=2割、AA項目「い」=4割、AA項目「う」=7割) EE項目 「か」を選択 分かりづらい説明で申し訳ございませんが、宜しくお願いいたします。