C言語関係掲示板

過去ログ

No.114.共用体


No.643

共有体
投稿者---恵子(2001/12/06 22:20:06)


こんな課題が出されたのですが、
「共有体を使用して、値を入力してその結果から、32ビット整数、実数の数値
の記憶形式について違いを記述せよ。プログラムを結果を提出」

なんか問題の意味というか、どんな感じのプログラムを作ればよいのか
悩んでいます。助言を頂けたらと思ってます


No.644

Re:共有体
投稿者---shu(2001/12/07 00:08:23)
http://c2c-1.rocketbeach.com/~finder_s/ccc/


>こんな課題が出されたのですが、
>「共有体を使用して、値を入力してその結果から、32ビット整数、実数の数値
>の記憶形式について違いを記述せよ。プログラムを結果を提出」

もしかしたら共有体ではなくて、共用体の間違いかもしれませんね。
共用体について調べてみてはどうでしょう。

No.645

Re:共有体
投稿者---B.Smith(2001/12/07 00:16:16)


私なりに解釈してみましたが、もし、ぜんぜん見当違いの事を言っていた場合は無視してください。

「共有体を使用して、値を入力してその結果から、32ビット整数、実数の数値の記憶形式について違いを記述せよ」

共用体は、型の違う変数であっても、領域を文字通り「共有」しますので、問題の意味は恐らく「共用体の一方の変数に数値を代入し、他方の変数でその詳しい内容を確認し、その内容から記憶形式の違いを明確にせよ」、という意味だと思います。

・記憶形式の違いについて調べることが目的なので、変数の入力方式にはこだわらなくても良いと思います。普通に共用体の変数に数値を代入した方が簡単です。

・整数型の記憶形式の場合、普通の2進法で表せます。実数型(浮動小数点)は、通常2進法で表せません(浮動小数点のフォーマットはマシンに依存)。型の違う変数を共用体にした場合、値を代入した側のフォーマットで領域に記憶されますので、実数で値をセットし、その内容を他方の(整数型の)変数で確認すれば良い、と思います。

例.
#include <stdio.h>
#include <stdlib.h>

void main(void )
{
	/* 共用体の定義						*/
	/* long、float共に32ビットの変数	*/
	union UN_TAG{
		long	lNumber;
		float	fNumber;
	} un;
	char		Buf[32+1];

	/* fNumberに数値をセット */
	un.fNumber = (float )3.141593;

	/* long型とfloat型の記憶形式が同じであるならば、同じ数値が	*/
	/* 表示されるが、実際には異なる数値が表示される。			*/
	printf("%lu    %f\n",un.lNumber,un.fNumber);

	/* fNumberのビットパターンを表示してみる */
	/* lNumberとfNumberの領域は同じであるため、lNumberのビット	*/
	/* パターンを見ることでfNumberのビットパターンを確認できる。*/
	/* この結果、fNumberの記憶形式に合わせて値を代入した場合通	*/
	/* 常の2進法では無いことが分かる(単制度浮動小数点の形式)	*/
	printf("long : %s\n",ltoa(un.lNumber,Buf,2));
}



No.648

Re:共有体
投稿者---kikk(2001/12/07 01:01:05)


ども。


>共用体は、型の違う変数であっても、領域を文字通り「共有」しますので、問題の意味は恐らく「共用体の一方の変数に数値を代入し、他方の変数でその詳しい内容を確認し、その内容から記憶形式の違いを明確にせよ」、という意味だと思います。

うーん。言われてみるとこっちのほうが適切なような気がしてきました。。

まあ、エンディアンや実数の内部表現についてのことも完全に無関係では
ない、ということで。。
# 点を稼ぐためには特に


では。

No.653

Re:共有体
投稿者---shu(2001/12/07 13:32:28)
http://c2c-1.rocketbeach.com/~finder_s/ccc/


共用体を共有体と間違えたり、32ビット整数といっても int か long
か解らない、実数といっても float と duble では使用される領域も
違ってきます。だからといって課題なのでそんな深いところまで理解
させようとしているようには見えません。

typedef union {
long l;
double w;
} Uni;

Uni uni;
int uni_size;
int uniLsize;
int uniWsize;

uni_size = sizeof(uni);
uniLsize = sizeof(uni.l);
uniWsize = sizeof(uni.w);

これで済むような気がするんですが・・・。

No.656

Re:共有体
投稿者---恵子(2001/12/08 15:33:49)


2つほど質問させてください。

(float)3.141593;の所ですが、上でfloatの定義をしているので、
(float)はいらないと考えて外してみたらエラーになってしまうのですが、
何故ですか?

printf("long : %s\n",ltoa(un.lNumber,Buf,2));
でlNumber→fNumberにしてfNumberのビットパターンを見る事はできない
のですか?

No.657

Re:共有体
投稿者---B.Smith(2001/12/08 17:31:42)

こんにちは。
      
>(float)3.141593;の所ですが、上でfloatの定義をしているので、
>(float)はいらないと考えて外してみたらエラーになってしまうのですが、
>何故ですか?
浮動小数点定数は、定数の後ろに何も付けていない場合、double型になります。今回のエラーは、
恐らく型の不一致の警告が出たものと思われます。
float型の定数にしたい場合、定数の後ろにFまたはfを付けます。

    /* fNumberに数値をセット */
    un.fNumber = 3.141593F;

No.645で私の載せたサンプルでは、接尾辞を使用せずにキャストしています。
これは、単なる私のクセでして、接尾辞を付けるよりもキャストした方がパッと見で分かりやすいので、(float)を付けています。

>printf("long : %s\n",ltoa(un.lNumber,Buf,2));
>でlNumber→fNumberにしてfNumberのビットパターンを見る事はできない
>のですか?

floatの記憶形式をlongで調べる場合は共用体を使用しましたが、逆の場合(long型の記憶形式を調べる場合)、
わざわざfloatの変数で調べる必要はあまり無いのでは…と思ったりしています。
共用体の使用にこだわる場合には、以下の処理で、lNumberの内容をfNumberで知ることができます。
float型の内容をlong型にメモリイメージのままコピーし、1ビットずつ上位ビットから表示していく、
いう処理なのですが、処理結果としては、前回サンプルでご紹介した関数ltoaを使った方法と変わりません。
ビット操作している分、こちらの方が、調べているんだぞ、っていう意思が伝わるかもしれませんね。

#include <stdio.h>
#include <memory.h>

void main(void )
{
    /* 共用体の定義                     */
    /* long、float共に32ビットの変数    */
    union UN_TAG{
        long            lNumber;
        float           fNumber;
    } un;
    int                 Idx;
    unsigned long       forShowBits;

    /* lNumberに数値をセット */
    un.lNumber = (long )123456789;

    /* unsigned long型の変数にfloat型の内容を   */
    /* メモリイメージのままコピー               */
    memcpy(&forShowBits,&un.fNumber,sizeof(long ));

    printf("Bits : ");

    /* ビット数分繰り返す */
    for(Idx = 0;Idx < 32;Idx++){

        if (forShowBits & 0x80000000)
            printf("1");/* 最上位ビットが1の場合、'1'を表示 */
        else
            printf("0");/* それ以外は'0'を表示 */

        /* 1ビット上位側にシフトする */
        forShowBits <<= 1;
    }

    printf("\n");
}




No.646

Re:共有体
投稿者---kikk(2001/12/07 00:34:30)


ども。


>「共有体を使用して、値を入力してその結果から、32ビット整数、実数の数値
>の記憶形式について違いを記述せよ。プログラムを結果を提出」

この問題は2つの部分に分かれます。
共用対を使用して..
(1)32ビット整数の記憶形式
(2)実数の記憶形式

(1)は、エンディアンのことについて解答を求められているようです。
(2)は、おそらく内部表現の確認(IEEE方式など、どういうビットパターンで
格納されているのか)です。

整数についても内部表現(2の補数といった話)を問う問題というのは作り得る
のですが、共用体の使用を要求していることから考えて、上記のように考え
られます。

実際に作る共用体は、intとunsigned char[4](intは32ビットであるとする)
とか、doubleとunsigned char[8](doubleは64ビットであるとする)をメンバ
に持つものをつくればよいかと。プログラムはintやdoubleに数値を入れて
からunsigned char[]の値を確認するものを作ればOKでしょう。なお、intの
ほうは入出力とも16進でやるといいかもしれません。

一番の問題は、「形式についての違いを説明せよ」の部分です。100点以上
とるためには、(1)(2)の両方とも、違いが出るような環境で実行しなければ
なりません。(1)の検証はPentium等のx86系のCPUと、PowerPCとかSparcとか
MIPS等が載っているマシン(後の2つはパソコンでは多分無い)とで比較すれば
いいので、比較的簡単なのですが、(2)は普通の人がさわる機会のあるマシン
はIEEEが多いため、検証のための環境をそろえるのはかなり難しいと思います。

自分の試した環境はこれこれで実際これこれになった、あたりで、お茶を
にごすのがいちばん簡単ですね。。


では。

p.s. 検索のためのキーワード
(1)は「エンディアン」
(2)は「浮動小数点(または実数)」&「内部表現」

No.654

Re:共有体
投稿者---恵子(2001/12/07 16:37:19)


すいません。共用体の間違いでした。
No.682

Re:共有体
投稿者---恵子(2001/12/09 23:51:57)


良く理解できました。皆様ありがとうございました

戻る


「初心者のためのポイント学習C言語」 Last modified:2002.01.11
Copyright(c) 2000-2002 TOMOJI All Rights Reserved