• ベストアンサー

最近のCPUのほとんどはリトルエンディアンかビッグエンディアンでしょうか?

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]; とすればいいでしょうか?

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

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

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

LongSecret
質問者

お礼

ありがとうございます♪ >PDPエンディアンとかその他の怪しいエンディアンはたぶん絶滅してると考えていいだろうから, 「いまあるプロセッサは全てビッグエンディアンかリトルエンディアン (かどっちでもいい)」と思っていいんだろうけど.... もっと端的にいえば「Windows ならリトルエンディアン」まで言えるだろう >ちなみにアラインメントの話では, アラインメントを 2のべきに仮定してしまえば「大きいほうから小さい方へのキャスト」は当然に安全です (ただしエンディアンには注意). 逆が危険なのも自明だし, そのときにはそれなりな演算をしなきゃならないことも明らか. この理解で本当にOKかどうかの確信がなかったので、これですっきりと解決しました! >でも, そこまで「速度にこだわらなければならない状況」って, ちょっと想像できないんだけどなぁ. こだわる必要はないかもしれません。ただ、どの道同程度の保証で同じ結果が得られるなら、無駄な処理はないほうがいいとは思います。 >short s=(c[0]<<8)|c[1]; >が安全かというとそうでもない. char から int にどう変換されるか, あるいはこの演算結果が short に入らなかったらどうなるのかは問題. 確かにそうですね。その辺はマクロをつかって、アラインメントに寛容でないCPUの場合ならば、キャストしつつ、とやることにします。 (そういえばWindowsAPIでつかうRGBマクロとか他にも色々そんな感じになってましたねw)

その他の回答 (2)

  • BLK314
  • ベストアンサー率55% (84/152)
回答No.2

どうしてそこまでエディアンに悩む必要があるのでしょうか? 通常のプログラミングであれば処理系に任せればいい話だと思います。 そもそも、CPUの違いを吸収するというのがC言語の (アセンブラに比し)大きなメリットでもあるわけです。 コンパイラ信用できないならオール・アセンブラで書く方が理にかなってます。 例えば、インターネットで異なるCPUでデータを通信したい等 特殊な場合には http://wisdom.sakura.ne.jp/system/winapi/winsock/winSock4.html のような関数が用意されています。 組み込み系等で用意されていなければ 自分で作ればいい話だと思います。 そこでバイトオーダーを吸収させて 後はバイトオーダー気にせずプログラミングする方が よほど理解しやすいプログラムになると思いますが・・・・ 上記にあるshortとcharの変換なら専用関数を作るべきでしょう。 そこでバイトオーダーを注意深くプログラミングする。 #ifdef 等を活用すれば 一つのソースにまとめ上げることもでき 管理も楽だと思いますが・・・・ そして変換が必要なら、関数を呼ぶ。 この原則を徹底させれば、 プログラムのあちこちでバイトオーダーに悩むこともなくなると思います。

LongSecret
質問者

お礼

ありがとうございます。 >どうしてそこまでエディアンに悩む必要があるのでしょうか? エンディアンにはそんなには悩んでいません。 異なるCPUでのデータ通信、異なるCPUでバイナリデータのファイル入出力(同じ独自の拡張子のファイルを作るとして)対応を考えるなら、先に考えておかなければ面倒なことになるためなのですが (逆に言うとそういう場合以外は仰る通りCを使って書く限り必要ないと思います) アラインメントの概念に対する理解がこれで正しいかどうかの方がたぶん重大です。後はそれが分かれば、おそらくエンディアンの問題に対する解も自然と得られます。 また、この点に関しては、アセンブリ言語で組むとしても、アラインメントに対する理解が完全でないと無理なはずです。 たとえばファイルをchar*バッファに一括読み込みして、それを後で切り分けるケースなどを考えたときに、それを簡単に、よりアラインメントが厳しい型へキャストできると非常に便利な場合があるはずです。 その場合、出力の時点でデータ順番を変えた方がいい可能性があるのではないでしょうか? また単なるshortとcharの交換などに対して専用関数を作る必要があるかどうかが重要です。 そもそもそういう状況というのは速度を求めている場合だからそうなるということなので、関数化するとオーバーヘッドが生じる可能性があるからです。(inlineキーワードはコンパイラに対する提案で、必ず埋め込まれるとは限らない) #ifdefと置換マクロなどを使うとしても、結果的にアラインメントに対する理解がないと組めません。

  • shinh
  • ベストアンサー率39% (363/926)
回答No.1

>Windows, Mac, Linuxに使われているCPUのほとんどはリトルエンディアンかビッグエンディアンでしょうか? そうですね。 ミドルエンディアン や PDPエンディアン は 少ないと思います。 参考に ウィキペディア ですが. http://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%87%E3%82%A3%E3%82%A2%E3%83%B3

LongSecret
質問者

お礼

ありがとうございます♪ やはりそうですよね。 大よそ安心できました。 しかし、上のコードも(最近のCPUに絞ったとして)やはり環境依存かなぁ… ああ、#include <windows.h>使ってるから環境依存とかいう問題はなしとして、考え方という点で、ですw この場合だと、問題あるとすればアラインメントまわりの問題を克服できてるかどうかにかかってると思うのですが …やっぱりアラインメントw 気になりますね。

関連するQ&A

  • リトルエンディアン→ビッグエンディアン

    (1)リトルエンディアン typedef struct recvData{  int a;  unsigned char b[16]; unsigned char c[8]; unsigned int d[4]; } recvData_t; recvData_t rData; (2)ビッグエンディアン typedef struct sendData{  int a;  unsigned int b[4]; unsigned int c[2]; unsigned int d[4]; } sendData_t; sendData_t sData; 上記のようなリトルエンディアンの構造体の各メンバのデータを、ビッグエンディアンの構造体の各メンバのデータにそれぞれ格納するには どうしたらよいでしょうか?

  • エンディアン: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.同様の問題で、ビッグエンディアンの場合は、どうすればよいかも、ご教示下さい。 よろしくお願いします。

  • #include <stdio.h>

    #include <stdio.h> struct st { char a[3]; short b; char c[7]; long d; char e[5]; }; int main(void) { printf("%d\n",sizeof(struct st)); return 0; } コンパイルオプションでアライメントを変化させながら(1,2,4,…) sizeof(struct st)の変化を見たいのですが、コンパイルする時に どのようにすれば良いのでしょうか?当方、gccを使用しております。 あと、ついでなんですが、警告オプションは-Wと-Wallしかないのでしょうか?

  • C++の問題で困っています。

    C++の問題で困っています。 今,C++の入門書を読んでその中の演習問題に取り組んでいるのですが、この本には答えがついていないみたいなので、問題で悩んでいます。 お力を貸してください。 問題 「文字列 s に含まれる最も先頭に位置する文字 c へのポインタを返す関数 strchr_ptr を作成せよ。型は char * strchr_ptr(const char *s, char c); とする。例えば、文字列 s が "ABSZXYX" で文字 c が 'X' であれば、返却するのは &s[4]である。 なお、文字 c が文字列 s に含まれない場合は NULL を返却すること。 」 です。 僕はこの問題に対して、以下のように答えました。 ヘッダのインクルードなどは省きます。 char *strchr_ptr(const char *s, char c) {         for(int i = 0; s[i]; i++)         if(s[i] == c)             return const_cast<char *>(&s[i]);     return NULL; } int main() {     char s[36] = "ABSZXYX";     cout << strchr_ptr(s, 'X') << "\n";     cout << &s + 4 << "\n"; } と書きました。 cout << &s + 4 << "\n"; はこの上の文で導き出したアドレスがあっているか確かめるものです。 ですが、これをコンパイルして実行すると、 ----------------- XYX 0012FFE0 ----------------- となり、関数側のほうはアドレス的な表記をしてくれません・・。 どうにかして、アドレス表記にしようとあれこれ考えたのですが、どうしても出来ませんでした。 どのようにしたらいいのか教えてください。 初歩的な質問ですが、よろしくお願いします。

  • 変数の扱える範囲

    C言語で、整数型変数の扱える範囲を確認するために 以下のような処理をしているのですが、どうもうまくいきません。 変数に入りうる最大値の値を、2進数の計算ではなく プログラム内で正しく扱われているか確認する方法はないでしょうか? ご存知の方、教えてください<(_ _)> 宜しくお願いいたします。 **********************************************  unsigned long long I; unsigned long A; unsigned int B; unsigned short C; printf("I:%d A:%d byte B:%d byte C:%d byte \n"    ,sizeof(I),sizeof(A),sizeof(B),sizeof(C)); A = B = C = 0; for(I = 0; I <= 4294967295; I++){ A++;B++;C++; if(I>= 4294967290 && I<= 4294967295)    printf("I:%d A:%d B:%d C:%d\n",I,A,B,C); }

  • C言語のソートについて

    C言語で下記のファイルの中身を昇順と降順で出力しようとしているのですが、ソートが上手くいっていない状況です。 どなたか修正点を教えて頂けないでしょうか? 「ファイルの中身」 2022/11/14 16:19:56 4+4,8.000000 2022/11/14 16:20:14 7+7,14.000000 2022/11/14 16:20:18 8+8,16.000000 2022/11/15 16:19:56 4+4,8.000000 2022/11/14 16:20:14 7+7,14.000000 2022/11/18 16:20:18 8+8,16.000000 2022/11/17 16:19:56 4+4,8.000000 2022/11/14 16:20:14 7+7,14.000000 2022/11/14 16:20:18 8+8,16.000000 「ソースコード」 #include <stdio.h> #include <string.h> #include <stdlib.h> int cmp_u(const void* a, const void* d) { return *(char*)a - *(char*)d; } int cmp_d(const void* a, const void* d) { return *(char*)d - *(char*)a; } int main() { int r,i,n; FILE* fp; char sin[9][1000]; fp = fopen("log.txt", "r"); if (fp == NULL) { printf("ファイルオープン失敗\n"); return -1; } for (i = 0; i < 9; i++) { fscanf(fp, "%s", &(sin[i])); } fclose(fp); printf("ASC or DESC: "); scanf(" %s", &ad); if (strcmp(ad, "ASC") == 0) { qsort(sin, 9, sizeof(char), cmp_u); } else { qsort(sin, 9, sizeof(char), cmp_d); } for (i = 0; i < 9; i++) { printf("%s\n", sin[i]); } return 0; }

  • ビッグエンディアンProgramの単体テスト

    以下の条件のCソース(ANSI準拠)をPC(OS:windows2K NTなど)上で単体テストする開発環境(ソフト)は,あるのでしょうか? ・ビッグエンディアンで作成されている ・実機CPUは,PowerPC603e ・テスト結果にてC0 C1カバレージ取得が必要 やはりPCのCPUは,インテル(リトルエンディアン)だからテストは,実機上でしかできないでしょうか? 大変へんな質問で申し訳ありませんが御回答ください。

  • ソケット通信時のエンディアン変換について

    現在、WindowsとLinux(Unix)でソケット通信を行い、データをやり取りするプログラムを作成しています。 ソースコードやコンパイルの環境は、 Windows側(Windows7):C言語(Windowsプログラミング)、VisualStudio2013でビルド&実行 Linux側:C++、g++(Cygwinを使用) 送信したいデータは、 Windows→Linuxはfloat型の配列に保持しているデータ Linux→Windowsはconst string型のデータ です。 (1)例として、送りたいfloatのデータが float a[3]; a[0] = 1.1; a[1]=2.2; a[2]=3.3 であるとします。(実際には負の値も考えられます) floatは4バイトなので、各要素でエンディアンを変えてa[0]からa[3]のデータを一括してLinux側にsendしたいと考えているのですが、どのように実装すればよいかが分かりません。 for(int i=0; i<3; i++){ //htonl(*(long*)&a[i]);でエンディアンを変換 //変換したものを何かしらの変数に保存 } //保存しておいたものをsend という大まかな流れだけは考えているのですが、実際どう実装していけばいいのか分からず困っています。 (2)(1)のデータを受信した側で元のfloatのデータに直す方法 (3)Linux→Windowsではstring型のデータを送りたいのですが、c_strを用いてchar型に変換したものをそのままsendしてよいのでしょうか? (char型は1バイトなのでエンディアンを変換する操作は必要はないでしょうか?) もし分かることがありましたら、教えていただけると助かります。 よろしくお願いします。

  • ポインタのsizeofについて

    C初心者です。 ポインタ宣言させた変数をsizeof()で値を取得させて 表示させてみました。 char *cp; short int *sp; int *ip; i = sizeof(cp); printf("%d\n",i); i = sizeof(sp); printf("%d\n",i); i = sizeof(ip); printf("%d\n",i); 結果は全て4となりました。 これはなぜですか? (ただの変数として宣言すれば1、2、4となります。この理由も理解できています。)

  • C++の関数テンプレートで分からないところがあります。

    C++の関数テンプレートで分からないところがあります。 C++の入門書を読んで勉強しているのですが、その演習問題(答えはついてないです)で、以下のような問題がありました。 ----------------------------------------------------- 配列の全要素の最小値を求める関数テンプレートを作成せよ。 teplate <class Type> Type minof(const Type x[], int n); という形で作ること。 なお、最も小さい文字列を求められるようにするために、const char *型に明示的に特殊化したものも合わせて作成すること。 ------------------------------------------------ という問題なのですが、これにたいして僕は以下のように答えました。ヘッダのインクルードなどは省きます。 template<class Type> Type minof(const Type x[], const int n) {     int min = 0;     for(int i = 1; i < n; i++)         if(x[min] < x[i])             min = i;     return x[min]; } template<> const char* minof<const char *>(const char x[][64], const int n) {     int min = 0;     for(int i = 1; i < n; i++)         if(strcmp(x[min], x[i]) < 0)             min = i;     return x[min]; } int main() {     const int n = 5;     int a[n];     char s[n][64];     for(int i = 0; i < n; i++){         cout << i + 1 << "番目---";         cin >> a[i];     }     cout << "文字列\n";     for(int i = 0; i < n; i++){         cout << i + 1 << "番目---";         cin >> s[i];     }     cout << "整数の最小値---" << minof(a, n) << "です\n";     cout << "文字列の最小値---" << minof<const char *>(s, n) << "です\n"; } これをコンパイルすると、エラーで 明示的な特殊化; 'const char *minof<const char*>(const char [][64],const int)' は関数テンプレートの特殊化ではありません と 'minof' : 1 番目の引数を 'char [5][64]' から 'const char *const []' に変換できません。 とでてしまいます。 色々探してみたのですが、解決できませんでした・・。 特に最初のほうのエラーがよくわかりません。ちゃんと特殊化してる気はするのですが・・。 間違っている箇所の正当を載せていただけるとわかりやすくて、ありがたいです。 よろしくお願いします!

専門家に質問してみよう