• 締切済み

エンディアンを知るには

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

みんなの回答

  • isle
  • ベストアンサー率51% (77/150)
回答No.11

#9です アラインメントの話も出てきてたのでそちらにも返答をしておきます。 アラインメントを処理系が勝手に決めて、しかも変更できないとしたら、「一気にバイナリデータを、構造体配列に読み込む」ことができなくなってしまう可能性がありますね。 バイナリデータに合わせてアラインメントを調整するとどうなるでしょう。 ゲームだとアラインメントを無くしてデータサイズを切り詰めたりすることもあるでしょうか。 インテル系のCPUならアラインメントがどんなでもあらゆるデータ型にそのままアクセスできます(若干の処理速度の低下はあります)が、例えばARMなら奇数バイトからのshort(16ビット)型のアクセスはハードウェアレベルで不可能です。 要するに「一気にバイナリデータを、構造体配列に読み込む」ことに拘るのがいちばん無駄なことです。

  • isle
  • ベストアンサー率51% (77/150)
回答No.10

#9です マクロを使ってもビッグエンディアンのマシンで実行時にバイト位置を入れ替える処理が不要にはならないのでは? リトルエンディアンに限定しても「一気にバイナリデータを、構造体配列に読み込む」のが期待通り動作することが【特定の条件下以外では】保証されませんし、言語規格で保証された範囲で読み書きするルーチンを作っておくほうが後々まで役に立つと思います。 どうしてもプログラム側で「一気にバイナリデータを、構造体配列に読み込む」以上に無駄なことしたくなければ、「一部がビッグエンディアン」のマシンを捨てて「一気にバイナリデータを、構造体配列に読み込む」ことのできるマシンに入れ替えてもらいましょう。

moritan2
質問者

お礼

ご回答ありがとうございます。 マクロを使ってもビッグエンディアンのマシンで実行時にバイト位置を入れ替える処理が不要にはならないのでは? これはバイナリーデータを機種にあわせて、最初から正しいエンディアンにしておけばいいです。画面の解像度など機種よりちがいますから、画像データなどバイナリデータはも機種ごとに違うものになるので、構造体のデータも機種ごとに違うものになるのは私の場合は気になりません。しかし、ソースはPS2、WII、DS、開発機のcygwinで同じ物を使いたいので、できればENDHIANはマクロで処理したいのです。 報告が送れて申し訳なかったのですが、WII用のコンパイラで __BIG_ENDIAN__ が定義済みマクロとして使えることを確認できました。またこれ以外のマシンはすべてリトルエンディアンですので、これで問題は解決いたしました。 前にお答えいただいた方々にもお礼を申し上げます。ありがとうございました。

  • isle
  • ベストアンサー率51% (77/150)
回答No.9

そもそも1バイトずつ読み書きすれば、実行側がビッグエンディアンかリトルエンディアンか意識する必要はないのでは? fread(&l, sizeof(long), 1, fp); とか b[0] = fgetc(fp); b[1] = fgetc(fp); b[2] = fgetc(fp); b[3] = fgetc(fp); l = *(long*)&b[0]; みたいなことをやらなければ良いだけ。 バイナリがリトルエンディアンと分かっているなら l = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]; で良くね?

moritan2
質問者

お礼

ご回答ありがとうございます。 これも、一気にバイナリデータを、構造体配列に読み込むのと比べて、無駄なコードが存在することになります。エンディアンやアラインメントはコンパイルの時点ではコンパイラは知っているはずなので、実行時になにかするのは無駄な処理のように思います。

  • DT200
  • ベストアンサー率38% (63/164)
回答No.8

質問ではマクロでとなっているので、回答として的確だと言えないかも知れませんが、 共通であるバイナリデータをネットワークバイトオーダー(ビッグエンディアン)に 統一してしまえば良いのでは?可搬性はぐんと高くなります。 そのために、バイナリデータを出力するときは htons、htonl でネットワークバイトオーダーに変換し、バイナリデータを読み込むときは ntohs、ntohl を使用してホストのバイトオーダーに変換する。 ソースは共通にできるはずです。

moritan2
質問者

お礼

ご回答ありがとうございます。 ご回答のやりかただと、バイトオーダーを変更するコードが無駄なコードになってしまいます。まあ、たいしたことはないのですが、単なるこだわりです。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.7

GCCであれば、__LITTLE_ENDIAN__のようなマクロがあらかじめ定義されたと思います。ただ、すべてのターゲットで一貫性のある定義が行われるかどうかは調査しないとわかりません。ただ、使用する処理系が限られていますので、上記のようなマクロが使えない場合でも、CPUを示すマクロなどを使って個別対応できるかと思います。(エンディアン判別用のヘッダを作るのがよいでしょうね) MIPSなどのバイエンディアンのCPUでは、バイトオーダーをコンパイルオプションで指定することになるので、むしろ確実に"あらかじめ定義されたマクロ"で判別できるはずです。

  • noocyte
  • ベストアンサー率58% (171/291)
回答No.6

> コンパイラはコンパイル時には次のような静的なデータをコンパイルする時には > エンディアンをわかっていなければならないはずと思うのですが。 > (以下略) バイエンディアン CPU の話ですか? 私も使ったことはないので推測ですが,デフォルトでは初期状態 (リセット直後) の エンディアンを使うのではないでしょうか.また,エンディアンを指定する #pragma もあるのかもしれません. 推測の上に余談ですが,データのエンディアンと,即値のエンディアンが異なる可能性 もありそうですね.(ああ,ややこしい….)

  • rabbit_cat
  • ベストアンサー率40% (829/2062)
回答No.5

一応、endian.h ていう、半標準のヘッダがあって、たとえば、 http://www.math.kobe-u.ac.jp/~kodama/tips-C-endian.html の「マクロによる判定」のようにすれば、いいことになってます。 あるいは、(中身は同じですが)boost/detail/endian.hppをincludeすれば、 BOOST_LITTLE_ENDIAN,BOOST_BIG_ENDIAN,BOOST_PDP_ENDIAN のどれかが定義されます。

  • noocyte
  • ベストアンサー率58% (171/291)
回答No.4

> コンパイラは gcc とお考えください。 手元には古い gcc しかありませんが,それでちょっと調べてみました. /usr/include/bits/endian.h で #define __BYTE_ORDER __LITTLE_ENDIAN というのがありました.これを使えばいいのでは? (確信なし) なお,#include するのは <bits/endian.h> ではなく <endian.h> です.

  • noocyte
  • ベストアンサー率58% (171/291)
回答No.3

> #ifdef BIG_ENDIAN エンディアンを定義している標準的なマクロというものはおそらくないのではないかと思います. (知っていれば私もとっくに使っていたはず.) だから,上記のようなマクロは,プログラマが処理系ごとに定義せざるを得ないでしょう. エンディアン判定関数で動的に判定すれば,それが不要になります. (といっても,それで節約できる手間はわずかですけど.) それに,(私は使ったことありませんが) エンディアンを動的に切り替えられる バイエンディアンの CPU というのもあります.そういう CPU に対しては, そもそも上記のようなマクロを定義することはできません. というわけで,エンディアン判定関数は無駄ではないと思います. エンディアン (Wikipedia) http://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%87%E3%82%A3%E3%82%A2%E3%83%B3

moritan2
質問者

お礼

ご回答ありがとうございます。 マクロは無いのですね。 となりますと、Makefile に CFLAGS += -D BIG_ENDIAN とでも記述してやるしかないのでしょうか? この記述自体はたいした手間でもありませんが、後から仲間に、 「そんなの、XXXXXX を使えばいいじゃん、なんでわざわざこんな定義をする必要があるの?」などと言われるとくやしいので質問しました。 コンパイラはコンパイル時には次のような静的なデータをコンパイルする時にはエンディアンをわかっていなければならないはずと思うのですが。 int xxx=0x12345678; xxxが 12 34 56 78 なのか 78 56 34 12 なのかはコンパイル時に決定していないとコンパイラは困るのではありませんか?

  • noocyte
  • ベストアンサー率58% (171/291)
回答No.2

ファイル内のどのデータがビッグエンディアンになるのかは 事前に (仕様として) わかっていて,CPU 側のエンディアンを 知りたいということでしょうか? C/C++ 関数・マクロ集 (処理系・OS 非依存) http://www5d.biglobe.ne.jp/~noocyte/Programming/CMacros.html ・エンディアンに関する関数・マクロ  ・実行時にエンディアンを判定する関数  ・エンディアンを変換 (big ⇔ little) する関数およびマクロ (CHAR_BIT 対応)  ・エンディアン名を取得する関数 (あらゆる4バイト・エンディアンおよび CHAR_BIT に対応) ・メモリ上のデータ操作関数・マクロ  ・データ (バイト列) をバイト逆順にする.

moritan2
質問者

お礼

ご回答ありがとうございます。 エンディアンを判定する関数というのは無駄ではないかと思います。 コンパイル時にはCPUが決まっているので、コンパイラはエンディアンを知っているはずであり、実行時に判定するコードは無駄なコードでないかと思います。 #ifdef BIG_ENDIAN // エンディアンの変換処理 #endif という感じで使えるマクロがありはず、と思うのですが。

moritan2
質問者

補足

コンパイラを特定しないといけませんでした。コンパイラは gcc とお考えください。CPU は Intel系(開発に使うPC)、ARM(DS)、MIPS(PS2、PSP)、PowerPC(WII) です。

関連するQ&A

  • エンディアンについて

    すみません。 教えてください。 リトルエンディアンからビッグエンディアンに変換しないと いけません。 エンディアンについては勉強したつもりですが、 どうしてもわからないことがあります。 ご存知の方、教えていただせんか? 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バイト)などは 意識せず、そのままバイナリ出力しても、ビックエンディアンで出力されると いうことでよろしいでしょうか? そうなると、エンディアンってなんだんだ???と混乱しています。 わかりにくい説明で大変申し訳ござませんが、 よろしくお願いいたします。

  • 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
  • ビッグエンディアンをPCで処理する問題

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

  • リトルエンディアン、ビッグエンディアンについて

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

  • 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
  • バイナリデータからの値の取得について教えてください

    今、バイナリデータから値を取りだそうとがんばっています。 しかし、うまくいかずに困っています。 困っていることは2点あります。 (1)バイナリデータにはリトルエンディアンで格納していると書いています。 まず、リトルエンディアンで書かれている場合、どのような処理を考えることが必要なのでしょうか? (2)バイナリデータには、 はじめに文字列(char)型4バイトで「RIFF]という値 次に32ビット符号なし整数で4バイトの数字、 次に4052バイトの構造体 などと収納されているようです。 このように入っているデータから値を取得するにはどのようにしたらよいのでしょうか? 全然できなくて困っています。 教えていただけないでしょうか? よろしくお願いいたします。

  • ビッグエンディアン環境で動作していたソフトウェア(暗号処理等を含む)を

    ビッグエンディアン環境で動作していたソフトウェア(暗号処理等を含む)を急遽リトルエンディアンの環境へ移植することになりました(コンパイラ等もリトルエンディアン用)。 具体的には、SHA、RSA、DHなどのアルゴリズムを含み、入力データ(128Byte程度)に対する電子署名の生成や検証を行うソフトウェアです。 ここで、移植するために修正すべき箇所を特定したいのですが、どのようにすれば良いか教えていただけないでしょうか? (ビット演算や型変換なども多用しています) よろしくお願いします。

  • Endianについて パート2

    elttacさん、Tacosanさん、terrar5さん、先日はありがとうございました。どうしても、疑問でならない部分がありまして、よろしければ、もう少しお付き合いよろしくお願い致します。 /--------------------------------------------------------------------------- エディアンとは、2 バイト以上の数値データを記録・転送するときの 「各バイトの並べ方」です。 たとえば,2 バイトの数値 0x0102(10 進数で 258)を考えましょう。ビッグエンディアンでは,この格納順は正順,つまり,   01 02 になります。 -------------------------------------------------------------------------------/ 1バイト目の0x02(2進数で 0000,0002)ですが、これも並び順によっては、0x20になっちゃったりしないのでしょうか? 1バイトでもビット単位で並び順が違えばさかさまになるような気がしまして。(1台のPC上では、バイト単位で処理しているので、大丈夫!? ネットワークでは、1bit単位でデータが転送されていますので???) ビット単位でもビッグエンディアンやリトルエンディアンみたいなのがあるのでしょうか?

  • エンディアン:2バイトのデータをShort intにしたいのですが?

    1.Intelの CPU リトルエンディアンでの、問題です。 バイナリファイルをバイト単位で読込み、これを16ビットの整数にしたいのですが、以下のようにコーディングしましたが、うまくいきません。解決方法をご教示下さい。 char s[2]; short int x;   // 16ビットの整数です // s[0] s[1]に、データを読み込みます。 x = (short)(s[0] + 256 * s[1]); 2.同様の問題で、ビッグエンディアンの場合は、どうすればよいかも、ご教示下さい。 よろしくお願いします。

  • リトルエンディアンのデータをテキスト変換して利用したい

    いつもお世話になっています。 ある観測生データが「リトルエンディアン」という形式のバイナリファイルです。 これをテキストに変換して、DBに取り込んで利用したいです。 環境としては、Accessの標準モジュールにその機能を作りたいです。 (Visual Basicなどは持っていないので^^;) やりたいことは、 1)当該のファイルを読み込んで、 2)テキストに変換した後、 3)テキストファイルに書き出して、 4)再度それを固定長の定義に従ってDBに取り込んで、 5)必要なフィールドのみ利用したい、 ということです。 この流れのうち、1)と2)がわかりません。 VBAで上記の1)、2)は可能でしょうか? 可能だとしたら、どのような方法がありますか? 3)以降は、Open やPutなどでテキストファイルを書き出すのと同じでよいでしょうか? なお、秀丸エディタのバイナリモードでファイルを開くと、次のように見えます。(行末に必ず","があります) 91,01,D7,07,02,00,07,04,00,00,A1,62,9F,53,1C,00, 75,00,0F,00,12,00,EA,00,E9,00,80,1F,96,6B,8A,43, 93,B9,92,74,93,E0,8E,73,8A,4A,89,5E,82,51,92,9A, いかがでしょうか?

専門家に質問してみよう