dポイントプレゼントキャンペーン実施中!

2000年あたり以降に出た
Windows, Mac, Linuxに使われているCPUのほとんどはリトルエンディアンかビッグエンディアンでしょうか?


また、たとえば以下のような方法でエンディアンを調べられると考えていいのでしょうか?(VC++です)

#include <windows.h>

void GetEndian4(char* c){

unsigned __int32 a=0x03020100;
BYTE *b = (BYTE*)&a, i=4;

while (i--) c[i]=b[i];

}

//////////

const char e[4]={};
GetEndian4( const_cast<char*>(e) );

//eが 0,1,2,3 になればリトルエンディアン
//3,2,1,0 になればビッグエンディアン
//PDP-エンディアンだと 2,3,0,1 …のはず

(または2択ならこれだけでも判断可能…?)

short s=1;
printf( *(char*)&s ? "リトルエディアン\n" : "ビッグエディアン\n" );


あとここでもアラインメントの問題が絡みますが、このように
アラインメントが(2のべき乗だとして)大きいであろう方から小さいであろう方にキャストする分には安全で、逆に
sizeof(short) == sizeof(char)*2 として

char c[2]={1,0};
short s=*(short*)&c;

というのは危険な場合がある、ということでしょうか?
また、その場合は
たとえばビッグエンディアンなら

short s=(c[0]<<8)|c[1];
とすればいいでしょうか?

A 回答 (3件)

PDPエンディアンとかその他の怪しいエンディアンはたぶん絶滅してると考えていいだろうから, 「いまあるプロセッサは全てビッグエンディアンかリトルエンディアン (かどっちでもいい)」と思っていいんだろうけど....


もっと端的にいえば「Windows ならリトルエンディアン」まで言えるだろうけど....
でも, そこまで「速度にこだわらなければならない状況」って, ちょっと想像できないんだけどなぁ.
ちなみにアラインメントの話では, アラインメントを 2のべきに仮定してしまえば「大きいほうから小さい方へのキャスト」は当然に安全です (ただしエンディアンには注意). 逆が危険なのも自明だし, そのときにはそれなりな演算をしなきゃならないことも明らか. ただし
short s=(c[0]<<8)|c[1];
が安全かというとそうでもない. char から int にどう変換されるか, あるいはこの演算結果が short に入らなかったらどうなるのかは問題.
    • good
    • 0
この回答へのお礼

ありがとうございます♪

>PDPエンディアンとかその他の怪しいエンディアンはたぶん絶滅してると考えていいだろうから, 「いまあるプロセッサは全てビッグエンディアンかリトルエンディアン (かどっちでもいい)」と思っていいんだろうけど....
もっと端的にいえば「Windows ならリトルエンディアン」まで言えるだろう


>ちなみにアラインメントの話では, アラインメントを 2のべきに仮定してしまえば「大きいほうから小さい方へのキャスト」は当然に安全です (ただしエンディアンには注意). 逆が危険なのも自明だし, そのときにはそれなりな演算をしなきゃならないことも明らか.


この理解で本当にOKかどうかの確信がなかったので、これですっきりと解決しました!


>でも, そこまで「速度にこだわらなければならない状況」って, ちょっと想像できないんだけどなぁ.

こだわる必要はないかもしれません。ただ、どの道同程度の保証で同じ結果が得られるなら、無駄な処理はないほうがいいとは思います。


>short s=(c[0]<<8)|c[1];
>が安全かというとそうでもない. char から int にどう変換されるか, あるいはこの演算結果が short に入らなかったらどうなるのかは問題.

確かにそうですね。その辺はマクロをつかって、アラインメントに寛容でないCPUの場合ならば、キャストしつつ、とやることにします。

(そういえばWindowsAPIでつかうRGBマクロとか他にも色々そんな感じになってましたねw)

お礼日時:2010/03/31 17:01

どうしてそこまでエディアンに悩む必要があるのでしょうか?



通常のプログラミングであれば処理系に任せればいい話だと思います。
そもそも、CPUの違いを吸収するというのがC言語の
(アセンブラに比し)大きなメリットでもあるわけです。

コンパイラ信用できないならオール・アセンブラで書く方が理にかなってます。

例えば、インターネットで異なるCPUでデータを通信したい等
特殊な場合には
http://wisdom.sakura.ne.jp/system/winapi/winsock …

のような関数が用意されています。

組み込み系等で用意されていなければ
自分で作ればいい話だと思います。

そこでバイトオーダーを吸収させて
後はバイトオーダー気にせずプログラミングする方が
よほど理解しやすいプログラムになると思いますが・・・・

上記にあるshortとcharの変換なら専用関数を作るべきでしょう。
そこでバイトオーダーを注意深くプログラミングする。
#ifdef
等を活用すれば
一つのソースにまとめ上げることもでき
管理も楽だと思いますが・・・・

そして変換が必要なら、関数を呼ぶ。
この原則を徹底させれば、
プログラムのあちこちでバイトオーダーに悩むこともなくなると思います。
    • good
    • 0
この回答へのお礼

ありがとうございます。

>どうしてそこまでエディアンに悩む必要があるのでしょうか?

エンディアンにはそんなには悩んでいません。
異なるCPUでのデータ通信、異なるCPUでバイナリデータのファイル入出力(同じ独自の拡張子のファイルを作るとして)対応を考えるなら、先に考えておかなければ面倒なことになるためなのですが
(逆に言うとそういう場合以外は仰る通りCを使って書く限り必要ないと思います)

アラインメントの概念に対する理解がこれで正しいかどうかの方がたぶん重大です。後はそれが分かれば、おそらくエンディアンの問題に対する解も自然と得られます。
また、この点に関しては、アセンブリ言語で組むとしても、アラインメントに対する理解が完全でないと無理なはずです。

たとえばファイルをchar*バッファに一括読み込みして、それを後で切り分けるケースなどを考えたときに、それを簡単に、よりアラインメントが厳しい型へキャストできると非常に便利な場合があるはずです。
その場合、出力の時点でデータ順番を変えた方がいい可能性があるのではないでしょうか?


また単なるshortとcharの交換などに対して専用関数を作る必要があるかどうかが重要です。
そもそもそういう状況というのは速度を求めている場合だからそうなるということなので、関数化するとオーバーヘッドが生じる可能性があるからです。(inlineキーワードはコンパイラに対する提案で、必ず埋め込まれるとは限らない)

#ifdefと置換マクロなどを使うとしても、結果的にアラインメントに対する理解がないと組めません。

お礼日時:2010/03/31 15:45

>Windows, Mac, Linuxに使われているCPUのほとんどはリトルエンディアンかビッグエンディアンでしょうか?


そうですね。 ミドルエンディアン や PDPエンディアン は 少ないと思います。

参考に ウィキペディア ですが.
http://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3% …
    • good
    • 0
この回答へのお礼

ありがとうございます♪
やはりそうですよね。
大よそ安心できました。


しかし、上のコードも(最近のCPUに絞ったとして)やはり環境依存かなぁ…

ああ、#include <windows.h>使ってるから環境依存とかいう問題はなしとして、考え方という点で、ですw

この場合だと、問題あるとすればアラインメントまわりの問題を克服できてるかどうかにかかってると思うのですが

…やっぱりアラインメントw
気になりますね。

お礼日時:2010/03/31 00:55

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!