• ベストアンサー

64ビットと32ビットの違い

C言語を使っているのですが、32ビット版のgccでコンパイルして実行できるファイルが、64ビット版のgccだと違う結果が出てきます。どちらのgccでも使える汎用性のあるファイルは書けないのでしょうか? 因みにstdio.h、math.h、stdlib.hのライブラリを使っていて、倍精度(double)と整数(int)を使っています。配列は宣言時に「*a」とでも宣言して、mallocで作っています。 漠然とした質問ですがよろしくお願いします。

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

  • ベストアンサー
回答No.7

ごめ、ソースみてわかる世界じゃないや(笑 むしろ、書いた人すごいなぁ。 LinuxならGDBが動くはずなので 地道にトレースして値のおかしくなる場所を特定して その結果から推測するしかないですね。 google検索したら日本語マニュアルあったのでぺたり GDB マニュアル http://flex.ee.uec.ac.jp/texi/gdb-j/gdb-j_toc.html

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (9)

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

「doubleのフォーマットが32bit版と64bit版で違う」ってことは当然あってもいいけど, 今どき普通はハードウェアの都合に合わせるだろうから「同じハードウェアならたぶん同じだろう」とは推測できると思います>#9. もちろん「推測」であって「断定」ではありませんが. 以下余談: 物理量を直接書くことは当然知ってるけど (というより「観測値なら直接書くしかない」はずだ), 「8.54×10^-7」を「8.54*pow(10.0, -7,0)」って書くのはいかがなものだろう. 普通はしれっと「8,54e-7」ですますものじゃないかねぇ. そうすれば Spon_HH は「定数行列*T_0」となるし, この「定数行列」そのものは (少なくとも現状はで) static const な配列で書けるのでお得. さらにいうと例えば z_HHplus を計算するところは関数として切り出せばいい (無駄な条件判断は消す) し, if(n_H_micro != NULL){ free(n_H_micro); n_H_micro=NULL; } も NULL かどうかの比較は無駄. もちろん malloc を使ったところで「訳の分からないところで違う領域に上書きされる」現象が回避されるわけではないです.

bechi0226
質問者

お礼

すみません。そのような書き方があるとは知りませんでした。

全文を見る
すると、全ての回答が全文表示されます。
  • titokani
  • ベストアンサー率19% (341/1726)
回答No.9

こりゃ確かにすごい。 で、こういう場合の定石として、 「問題が発生する最小限のコードに絞り込む」 ってのを地味にやるしかないかと。 可能性として考えられるのは、int<->doubleの変換で、intが32bitか64bitかで違いが生じるので、そのからみとか。でも、すべての計算をきっちりdoubleでやっていれば、この問題は起こらない。 あと、doubleのフォーマットが32bit版と64bit版で違う・・ってことはある話なのかなぁ。

全文を見る
すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.8

これを人間が書いたんだとしたら確かに「すごい」けど>#7, その努力は別のところに使うべきじゃなかったかなぁ.... ene_HA=(double *)malloc(sizeof(double)*6); とか Spon_HH[21][0]=8.54*pow(10.0,-7.0); とか, 人間が書いたとは到底信じられない. まずは「人間が読めるコード」に修正すべきなのかもしれんが, こんなの触りたくない. 持って来たら突っかえすよ, こんなの. ま, 他人の協力が得られないことを前提に, #7 で挙げられている gdb を使って自力でなんとかしてください. gcc でコンパイルするときに -g オプションを付けてくださいね.

bechi0226
質問者

補足

確かに6個の配列をmallocで作るのはやり過ぎかもしれませんが、メモリを確保しないと訳の分からないところで違う領域に上書きされることがあったので怖いんです。Spon_HHについては物理量を実験値、理論値からダイレクトに代入することがあることを知って下さい。

全文を見る
すると、全ての回答が全文表示されます。
  • titokani
  • ベストアンサー率19% (341/1726)
回答No.6

ごくごく普通に書けば、32ビットでも64ビットでも同じく動くはず。 結果が異なるというのは、やはり変な書き方をしていると思われるわけで、ソースを提示するのが一番です。

bechi0226
質問者

補足

ソースを置きましたのでURLをお報せします。 遅くなって澄みません。 http://bechi0226.web.fc2.com/yotsuba.html

全文を見る
すると、全ての回答が全文表示されます。
回答No.5

#2 への 補足にあるけれどmallocのサイズ不正でNaNになるのかな? 0除算ならあるかもしれないけれど。。 まぁ、ソースコードと結果を見ないことには予想も立ちませんね。 結果が違うとだけいわれても、 32bitの時、おかしい 64bitの時、おかしい 両方、おかしい と三通りのあるわけで、ソースコードもなしで、答えなんか出ません。

全文を見る
すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

って~か, malloc を使うときに忘れずに stdlib.h をインクルードすればいいだけじゃないのかなぁ>#3. 普通, sizeof を使わずに malloc ってあんまりしないよね. 要するに「きちんと規格に従って書く」間は問題なし.

全文を見る
すると、全ての回答が全文表示されます。
回答No.3

回答1に引き続き。 メモリ確保にmallocをお使いとのこと。 「malloc 64bit」で検索すると分かるとおり、64bit環境でのmallocの使い方で悩んでいるケースは結構あります。 mallocは型指定せずにメモリサイズを自分で指定しないといけないため、32bitのときと定義サイズの違うデータ型で使おうとすると正常に動作しません。 ここ↓の回答1が参考になります http://okwave.jp/qa1683511.html sizeof(データ型)で抽象的に指定してやればいいのですが、 いずれにしても、malloc ~ freeはプログラム初心者には難しい概念だと思われます。 gccをお使いでしたら、CではなくC++言語にして、new ~ deleteでデータ型を指定したメモリ確保をすれば、その部分では悩まずに済むはずです。

bechi0226
質問者

補足

すみません・・・size_tを使うのは分かるのですが、応用として2次元配列を作るのにはどうしたら良いのかが分かりません。

全文を見る
すると、全ての回答が全文表示されます。
  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.2

こんなソースを書いたところ、こんな風に結果が異なった、 というような、具体的な質問ができますか?

bechi0226
質問者

補足

2次元配列で行列を作ってから逆行列を計算しているとnanが出てきます。

全文を見る
すると、全ての回答が全文表示されます。
回答No.1

ポインタのサイズが違います。 32bit環境は、メモリのアドレスを指定できる数が、2の32乗≒43億。 つまり、理論上約4ギガバイトのメモリにアドレスを割り振ることができます。 32bitウィンドウズでのメモリ上限が4GBというのはこのためです。 メモリの「ここ」という情報を格納するポインタ変数において、それを表現するのに、32bit環境の場合、4バイトになります。 64ビットの場合、8バイト。 C/C++をgccでコンパイルした場合、各環境のCPUが直接読めるネイティヴコードが生成されるゆえ、32ビット用、64ビット用と明確に違うバイナリが出てきます。 >どちらのgccでも使える汎用性のあるファイルは書けないのでしょうか? 自分で書くソースは共通のもので大丈夫なはずです。 コンパイラ(gcc)が頑張ってそれぞれに合わせて翻訳するだけなので。 「どちらの環境でも使える汎用性のある実行ファイルはできないか?」 という意味の質問でしたら、 Windowsの場合に限ると、64bitのほうには32bitのプログラムを実行するエミュレーターが搭載されているので、32bitのほうでコンパイルすればどちらの環境でもOKになります。 その他のOSの場合、それぞれ違いますが、エミュレーターのような特別な仕組みが入っていない限り、基本的には不可です。 OSを問わず、環境を問わず実行できるものを目指すのでしたら、Javaのほうが良いと思います。

bechi0226
質問者

補足

詳しいご説明ありがとうございます。 違いがよく分かりました。 OSはUNIXの多分Redhatです(管理者ではないので過去の記憶です)。 重ねての質問になりますが、64ビット用に書き換えるにはどうしたら 良いのでしょうか? あと、Javaは学術計算に使えますか?

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • Cygwinをいれました

    アルサイトからいれました、でもヘッダファイルがなくてgcc でコンパイルすると #include <stdio.h> #include <math.h> などで引っかかってコンパイルがとおりません。ヘッダファイルだけ欲しいのですが、どっからとってこれませんか?

  • コンパイル

    ubuntuで、 gcc (ファイル名).c とコンパイルをしようとすると、 error: stdio.h: No such file or directory error: math.h: No such file or directory が出てきてしまいます。どうやってコンパイルしたらよいのでしょう?初心者ですのでよろしくお願いします。

  • 64bit系でのmalloc

    こんにちは itanium2の乗っているマシンでcのプログラムをつくっています。 gccでコンパイルしているのですが、 warningが出てコンパイルができません。 以下のようなエラーです。 warning: cast to pointer from integer of different size 引っかかっている場所は、 double *ini=(double *)malloc(sizeof(double)*1000000); という場所です。配列iniのサイズが小さいうちは以下のように double ini[10000] とすれば、通るのですが、大きなメモリ領域を確保しようと mallocを使うと上のようなエラーが出て、コンパイルできません。 調べてみると、64ビット系で起こるエラーであるということは わかったのですが、回避の仕方がわかりません。 どなたかご存じの方がいらっしゃったらお教えください。 OSはレッドハット8でカーネルは2.4.24です。

  • 分割ファイルのコンパイル

    $gcc Bprop.c init.c prop.c state.c head.h main.c memory.c read.c -lm -g 以上のように複数のファイルをコンパイルしたら以下のようなエラーが表示されました。 gcc: compilation of header file requested この場合は自分で作成しているヘッダファイルに問題があるのでしょうか?またヘッダファイル内では以下のヘッダを読み込んでいます。 stdio.h string.h stdlib.h math.h time.h ヒントをよろしくお願いします。

  • 2つのvoid関数でmallocを使うと2step目でセグメントエラーが出る

    プログラムのmainを見やすくするためにサブルーチンとしてvoid関数を使っているのですが、その中でmallocでメモリを確保して配列を作ろうとするとエラーが出てしまいます。概略を書くと #include <stdio.h> #include <math.h> #include <stdlib.h> //voidの宣言 void a(double* ,double*, double,); void b(double* ,double*, double,); main(){ double *c,*d,e; double *f,*g,h; c=(double *)malloc(sizeof(double)*N) //Nは適当な整数です d,f,gも同様の処理 色々な作業 while(適当回数繰り返します){ a(c,d,e); b(f,g,h); 色々な作業 } } void a (double* c, double* d, double e){ double **i,*j,; int k; i=(double **)malloc(sizeof(double *)*M) //Mは適当な整数です for(k=0;k<=M;k++){ i[k]=(double *)malloc(sizeof(double)*M) //Mは適当な整数です } jも同様にメモリ確保 様々な作業(逆行列の計算など) } void bはaとほとんど同じです。 mallocで二次元配列や配列を作っています。勿論同じ文字は使っていません。 以上のようなプログラムでgccは通ります。でも実行するとwhile内での1step目は上手くいくのですが、2step目のb内での始めの(double *)malloc(sizeof(double)*L)(Lは適当な整数です)で、つまりメモリ確保でセグメントエラーが出ます。両者とも片方を削るとエラーは出ません。1step目は何故上手くいくのか、2ステップ目で何故ダメなのかが分かりません。皆様の御教授をお願いします。

  • ポインタ配列の動的確保

    ポインタの配列の動的確保について教えてください。 入力した数値をポインタ配列に入れるプログラムです。 下記のように書いてみました。(見づらくてごめんなさい) #include<stdio.h> #include<stdlib.h> #define kensu 3 main() { char abc[kensu+1]={'A','B','C','\0'}; char *ptr[kensu]; int i; printf("3つの整数を入力して下さい。\n"); for(i=0;i<kensu;i++){ ptr[i]=(char*)malloc(sizeof(char)*10); if(ptr[i]==NULL){ printf("メモリの取得に失敗しました"); exit(1); } printf("整数%c:",abc[i]); fgets(ptr[i],10,stdin); if(ptr[i][strlen(ptr[i])-1]=='\n') ptr[i][strlen(ptr[i])-1]='\0'; } for(i=0;i<kensu;i++) free(ptr[i]); } ちゃんと動いているようです。 しかし、ポインタ配列の動的確保をネットで調べてみると、ポインタのポインタ(?)を使って、下記のように2度mallocしています。 #include <stdio.h> #include <stdlib.h> #define N 3 int main(void) { char** arr; int i,j; arr = (char**)malloc(N * sizeof(char*)); /* ポインタ配列を確保 */ /* 配列の要素それぞれにつき、メモリ領域を確保 */ for(i=0;i<N;i++) arr[i] = (char*)malloc(N * sizeof(char));   ・・・ ポインタの配列を宣言して、配列の各要素に動的確保するのと ポインタのポインタを宣言し、ポインタ配列を動的確保して、再度配列の要素に動的確保するのとでは、何か違いがあるのでしょうか? ポインタのポインタを宣言し、ポインタ配列を確保する必要性が良く分かっていないのです。 ネット等で調べて見たのですが、理解力がないのかよく分かりませんでした。 どうか教えてください。

  • 取ってこれないメモリのはずのmallocの動作

    こんにちは.mallocの動作,及びコンパイルの仕様について質問です. 以下のような.cのプログラムを書いてgccでコンパイルして実行してみました. #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char **argv) { int size = 0; int *tmp = NULL; while(1){ printf("Size %d\n", size++); tmp = (int *)malloc(size * 1024 * 1024); usleep(10000); free(tmp); } } このプログラムだと,heapから取ってこれないぐらい大きいメモリだとなんか起きるのかな?どれぐらいまで取ってこれるのかな?という興味でやってみたのですが, 1)32bit, 64bit ubuntu のgcc (バージョンは覚えてないですけど一番updateされてると思います)では永遠に回り続け, 2)Mac のgccだとSize=2048以降,つまり2GB以降で a.out(1145,0x7fff73a1b310) malloc: ***mach_vm_map(size=18446744071562067968) failed (error code=3) *** error: can't allocate region というエラーをはきます.(プログラムは回り続けます) a. この違いはgccの違いからくるという理解でよろしいですか?Macでの2GBというのもコンパイル側の制約なのでしょうか? b. ubuntuでは実際何が起こってるのでしょう?1000GBとか絶対取れないですけど回ってますし. c. ubuntuで実際に何が起こってるかを確認する方法はありますか.アセンブラとか吐かせるのでしょうか? お時間のあるときに回答してもらえたらと思います.

  • c言語のコンパイルについて教えてください。

    Unixとwindows98を使用しています。 #include<stdio.h> #include<math.h>    (以下 省略)  と、c言語のプログラムをして、コンパイルを、gcc ファイル名.c  と するのでしょうか。 cl ファイル名 -lm   とするのでしょうか。  どうすれば良いか、教えてください。 説明が下手で申し訳ございません。 お答えを待ってます。  

  • solaris9に32ビットのapache,phpをinstallしたい

    solaris 8で32ビット版gccでapache.php,あるモジュール(phpで使うxxx.soファイル) を構築して,solaris8では問題なく動くのですが solaris 9で構築することになり,apache,php等をinstallしましたが sokaris9ではgccが基本的に64bitなので,apache,phpも64bitでinstall されたようです が,あるモジュールは,32ビットしか対応していないので, 普通にgccしてもELFのエラーがでたので gccの-m32オプションを付けてコンパイルしてコンパイルは通りました (xxx.soは作成完了) しかし,実際cgiを起動して,phpからそのxxx.soの中の関数郡を使おうとするとELFのエラーがでました そこで,apache,phpを32ビットでinstallすればいいのではと思いましたが,Makefileをいじったりしていろいろとやってみましたが うまくいきません gccは3.4.4のsolari9 64bit版のパッケージを入れています solaris9でgccが64ビット環境で,apache,phpのinstallのやり方を 教えてください

  • C言語(C89)での文字列代入

    C言語文法のうち、gcc 拡張機能を含まない C89 規格で、 文字列の「= での代入」は可能なんでしょうか? strcpy が必要だと思っていました。 #include <stdio.h> #include <stdlib.h> #include <string.h> int main(){ char *p; p=malloc(30); p="Hello"; printf("%s\n",p) return 0; } gcc で gcc -Wall -std=c89 -pedantic-errors としてコンパイルしても なんのエラー表示もなく正常に動作しています。 これまでC89では「=での文字列代入」は(宣言時を除いて)できない と思ってたので不思議です。 ちなみに、free(p) を return 0; の前に入れると、エラーになります。 情報処理技術者試験(試験で要求される規格はC89)を受ける知り合い から質問されたのがきっかけです。