質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

UNIX

UNIXとは、AT&Tのベル研究所で開発されたコンピューター用のマルチユーザー・マルチタスクのオペレーションシステム(OS)です。政府や教育機関や研究所で広範囲に採用されています。

FORTRAN

FORTRAN(フォートラン)は科学時術計算に向いた手続き型プログラミング言語です。 並列計算の最適化が行いやすい特性上、数値予報および気候モデルなどの大規模な計算を行う分野のスーパーコンピュータで使われています。

Q&A

3回答

2676閲覧

共用体でエンディアン変換を行いたい。

nori0519

総合スコア16

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

UNIX

UNIXとは、AT&Tのベル研究所で開発されたコンピューター用のマルチユーザー・マルチタスクのオペレーションシステム(OS)です。政府や教育機関や研究所で広範囲に採用されています。

FORTRAN

FORTRAN(フォートラン)は科学時術計算に向いた手続き型プログラミング言語です。 並列計算の最適化が行いやすい特性上、数値予報および気候モデルなどの大規模な計算を行う分野のスーパーコンピュータで使われています。

0グッド

0クリップ

投稿2020/11/05 07:17

編集2020/11/05 23:53

前提・実現したいこと

共用体を用いて、エンディアン変換行う関数を作ろうとしたところうまくいかない状態です。

実行結果

別のスクリプト(FORTRAN)でこの関数を呼び出して、実行したところ以下のような数値がでました。
floatの値には123.456のような数値が入っています。

-1.47179405E+09

該当のソースコード

c

1#include <stdio.h> 2#include <stdlib.h> 3 4union fl { 5 char cvar[4]; 6 float fvar; 7}; 8 9float convert_endian_(float *x) 10{ 11 union fl uni_fl; 12 //変換した後の数値 13 float fvar_ce; 14 15 uni_fl.fvar=*x; 16 //ビックからリトルへの変換 17 //float型で取り込む 18 fvar_ce=uni_fl.cvar[0] << 24 | uni_fl.cvar[1] << 16 | uni_fl.cvar[2] << 8 | uni_fl.cvar[3] << 0; 19 return fvar_ce; 20}

FORTRAN

1 REAL CONVERT_ENDIAN,X,Y 2 X=123.456 3 Y=CONVERT_ENDIAN(X) 4 5 WRITE(6,*) Y 6 7 STOP 8 END

試したこと

共用体の使い方やエンディアン変換について調べましたが該当する記事が見つからず、どのようにすれば良いかわからない状態です。
なにかヒントでも良いので、ご教授いただければ幸いです。
よろしくお願いいたします。

補足情報(FW/ツールのバージョンなど)

使用OS:macOS

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2020/11/05 07:38

> 別のスクリプトでこの関数を呼び出して、実行したところ以下のような数値がでました。 状況が良く分かりません。エンディアンを変えるこの関数を呼び出し、上位下位を反転させたら、それは変な数値になって当然です。呼び出す前のfloatの値と、その操作を行っているコードを質問文中に追記して提示しましょう。
nori0519

2020/11/05 07:42

ご連絡ありがとうございます。 そのように追記いたします。
dodox86

2020/11/05 07:52 編集

[編集 2020/11/05 16:46]で編集された質問文を読んで: 検証できる環境にないのでコメントのみですが、FORTRAN側でセットした123.456の浮動小数点数は、完全に同じ値でC言語側の関数に渡ってきているのでしょうか。互換性はあるのでしょうか。ビットパターンが違うということはありませんか。そうであるとエンディアンだけの問題ではなく、FORTRANの処理系の問題も関係するはずです。
nori0519

2020/11/05 07:57

ご連絡ありがとうございます。 互換性はおそらくあるかと思われます。なるほど。FORTRANの処理系の方調べて見ます。
dodox86

2020/11/05 07:59

「おそらく」ではダメなのではないかと。ビットパターンが合っていないと正しく扱えないはずです。FORTRAN/C言語のインターフェースが用意されているかもしれませんが。
nori0519

2020/11/05 08:08

>dodox86 ビットパターンがc言語とFORTRANの間で合っていないということでしょうか。それを確かめる方法はございますか?
dodox86

2020/11/05 08:23

エンディアンの変換だけなら、上位下位のバイトをひっくり返せばいけます。 float、doubleなどのNビット浮動小数点数の変数についてもはやり、メモリ上に展開している複数バイトをロードするときにはエンディアンは関係するはずですが、今回はお使いのFORTRAN処理系とのやり取りが生じているので、(私が考える限りは)それが関係するとは限りません。一般的にはC言語など他のプログラミング言語とやり取りする上で何か方法が提供されていたりします。それは処理系にもよります。 C言語間のインターフェースを考えるなら、そのFORTRAN処理系のマニュアルを確認してください。しかしなぜエンディアンの変換をしなければいけないのでしょうか。どこかにそうしろと指示があったのでしょうか。お使いのFORTRANの処理系の名前やCコンパイラの詳細を書くと、有識者の方から回答を得られるかもしれません。私がコメントできるのはこれくらいです。
tatsu99

2020/11/05 09:17

同じマシン内でのC言語とfortarnの話なら、そもそもエンディアン変換は必要ありません。 エンディアン変換が必要と判断されたのは何故でしょうか。 エンディアン変換が必要なのは例としてSPARC系のマシンとインテル系のマシンとでデータのやり取りをする場合です。
pepperleaf

2020/11/05 11:25

tatsu99さんの指摘のように、同じマシンなら、通常、エンディアン変換は不要。それより、Cと Fortranの内部表現の方が問題かと。
nori0519

2020/11/05 23:29

>dodox86,tatsu99,pepperleaf ご連絡ありがとうございます。 同じマシンであればエンディアン変換が不要なのですね。私は単純に変換されるかどうかを確認してみたかったのですが....(同じマシンであるので上位下位のバイトがひっくり変えること) 内部表現ですか…出力の数値の内部表現が誤っているということでしょうか。
guest

回答3

0

C

1#include <stdio.h> 2 3union fl { 4 char cvar[4]; 5 float fvar; 6}; 7 8float convert_endian_(float *x) 9{ 10 union fl fl_in; 11 union fl fl_out; 12 13 fl_in.fvar = *x; 14 15 fl_out.cvar[0] = fl_in.cvar[3]; 16 fl_out.cvar[1] = fl_in.cvar[2]; 17 fl_out.cvar[2] = fl_in.cvar[1]; 18 fl_out.cvar[3] = fl_in.cvar[0]; 19 20 return fl_out.fvar; 21} 22int main(){ 23 float x = 123.456; 24 float y; 25 26 27 y = convert_endian_(&x); 28 29 printf("%08X\n",*(int*)&x); 30 printf("%08X\n",*(int*)&y); 31}

int型として16進表示すれば、反転していることが分かると思います。
printfの引き数にfloat値をそのまま書くと、doubleに変換して関数に渡るので駄目です)

投稿2020/11/05 09:00

otn

総合スコア85901

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nori0519

2020/11/05 23:36

ご回答ありがとうございます。 そのように入力したところ、うまくいきました。 ただ、FORTRAN上から呼び出すと不自然な値となりますので、FORTRAN上の問題を確認して参ります。
guest

0

質問のコードには次のような明らかな間違いがあります。
・char cvar[4]; なので、符号付きの char である uni_fl.cvar[1] などが
符号拡張されて int になるので上位ビットが全部 1 になる。
・<< と | の演算結果が int であり、それを float に代入するとき、
全く別のビットパターンになる。

次のコードではどうなりますか?

union fl { char cvar[4]; float fvar; }; float convert_endian_(float *x) { union fl a, b; a.fvar = *x; for (int i = 0; i < 4; i++) b.cvar[i] = a.cvar[3-i]; return b.fvar; }

どういう値になってほしいのですか?

投稿2020/11/05 08:58

kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nori0519

2020/11/05 23:34

ご回答ありがとうございます。 c言語上ではうまくいきました。ありがとうございます。 ただ、FORTRAN上では不自然な文字列となりましたので、FORTRAN上を確認してまいります。
guest

0

fvar_ce=uni_fl.cvar[0] << 24 | uni_fl.cvar[1] << 16 | uni_fl.cvar[2] << 8 | uni_fl.cvar[3] << 0;

float変数のままで代入してはダメです。
このビットパターンをそのまま入れなければならないので、

char* s =(void*)&fver_ce;
s[3]=なんたら[0];
s[2]=なんたら[1];
s[1]=なんたら[2];
s[0]=なんたら[3];
return fver_ce;

ということをします

投稿2020/11/05 07:25

編集2020/11/05 07:51
y_waiwai

総合スコア88042

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nori0519

2020/11/05 07:37

ご回答ありがとうございます。 >char* s =(void*)fver_ce; こちらは何をしている部分になるのでしょうか。
y_waiwai

2020/11/05 07:41

fver_ceのアドレスをsに代入しています ちと裏技的な操作になりますが、C言語ではこれで通ってくれます
nori0519

2020/11/05 07:48

ご連絡ありがとうございます。 そのように変更したところ、以下のエラーが発生いたしました。 ``` error: operand of type 'float' cannot be cast to a pointer type char* s =(void*)fvar_ce; ```
y_waiwai

2020/11/05 07:52

ああ、間違ってます。すんません char* s =(void*)&fvar_ce; ですね。 #回答も修正しときました
dodox86

2020/11/05 07:53 編集

[修正されたのでコメント削除]
dodox86

2020/11/05 07:57

正直、こちらのご回答の意図が分からないのですが、unionでcharの配列を4要素とっているので、 union fl { char cvar[4]; float fvar; }; union fl uni_fl; uni_fl.fvar = *x; fvar_ce = uni_fl.cvar[0] << 24 | uni_fl.cvar[1] << 16 | uni_fl.cvar[2] << 8 | uni_fl.cvar[3] << 0; 一応、上位下位を反転させようというコードは合っているのではないでしょうか。
nori0519

2020/11/05 07:59

ご連絡ありがとうございます。 そのように修正したところ、うまく通りました。 実行結果は1.51849984E+35となり、不自然な数値となります。
y_waiwai

2020/11/05 08:01

それをfloatに代入するってところでおかしくなります intの変数ならそれで行けるんですが
nori0519

2020/11/05 08:03

>dodox86 ご連絡ありがとうございます。 なるほど。反転させた後の数値が不自然になるのは無理やりバイトオーダ変換をしたからでしょうか。
dodox86

2020/11/05 08:06

ああ、y_waiwaiさんのご指摘のように。浮動小数点数特有のビットパターンに関わることでしたら、きっとそうですね。FORTRAN側から渡されてくるのがどういう値になるか分かりませんので、混乱を避けるためにも、以降コメントを控えます。
nori0519

2020/11/05 08:06

>y_waiwai ご連絡ありがとうございます。 intをキャストしてintで出力するということでしょうか。
y_waiwai

2020/11/05 08:41

まあ、FORTRANの浮動小数点形式がCのそれとあってるのかどうかって問題はありますな。 そこらへん確認しました?
nori0519

2020/11/05 08:55

>FORTRANの浮動小数点形式がCのそれとあってるのかどうか REAL型とfloat型があっているのかどうかということでしょうか。
y_waiwai

2020/11/05 09:09

そゆことですね。 浮動小数点形式は複雑な構造ですんで、そのフォーマット(?)が一致してないとビットパターンを同じにしてもダメですよ
nori0519

2020/11/05 23:51

>y_waiwai ご連絡ありがとうございます。 確認したところ、一致していたようです。 他に誤っているところがないか、確認してまいります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問