ものづくりBLOG blog page

第4章 何もしない(3):式−型変換−

2011-01-01 (Sat) 04:02
H8+C言語入門:第4章 何もしない(3):式−型変換−
 
 第4章の式について、補足をします。
 式を処理する時、変数や定数の型について、注意を払う必要があります。
 式(文)に現れる変数や定数が全て同じ型であれば、全く問題なのですが、やはりプログラ
 ムを書く上では、そうは問屋が卸してくれない時もあります。そんな時は、ここでしっか
 り覚えが型変換の知識を使って解決してください。
 
 
 ■型変換の基礎
  異なる型の被演算数は、式の中に現れると、少数の規則に従って共通の型への変換が行
  われます。これが型変換の基礎なのですが、何を言っているのだろう、って感じがしま
  せんか?例を使って説明しますね。例えば、次の処理を見てみます。
 
   float f;
   int i;
   f = 10.123;
   i = 10;
   f = i + f;
 
  式「f = i + f;」の右辺、i + fを見てみます。
  ここでの型変換は、整数iを浮動小数点数に変換してから、fの値と加算します。
  では、改めて、型変換とは、
   つまり、情報を失うことなく、
       より狭い被演算数から、
       より広い被演算数へ変換する、ことです。
 
  でも、ここでちょっと混乱させてしまいますが、こんなことは実はできます。
  それは、より長い整数型をより短い整数型へ代入するとか、
      浮動小数点数型を整数型に代入するとか、
  (前述とは逆に)情報を失うことになり得る式です。
 
   例 i = f;
 
  これは、文法的に許されます。
  でも、コンパイルする時に警告が出ます。警告が出たら、その内容をよく読んで対応し
  てください。
 
 
 ■型変換の注意事項
  型変換の現場で、何が起こるのか・・ちょっと気になることを、ここにまとめます。
 
  暗黙の算術変換は、およそ予期通りに行われます。あまり無茶なことはしないというこ
  とです。一般的に(前述の通り)、+や*の様な二つの被演算数を扱う演算子(二項演算子)
  に異なる型の被演算数が現れると、低い型(狭い型)が、高い型(広い型)の方へ格上げさ
  れてから、実際の演算(処理)が行われます。そして、その結果は、高い型(広い型)の方
  になります。
 
  これを本格的に書き出すと結構、難解な文章になるので、大まかな規則として、以下の
  様にまとめます。
   片方の被演算数がdoubleなら、他方をdoubleに変換する。
   そうでなくて、片方の被演算数がfloatなら、他方をfloatに変換する。
   そうでなければ、charとshortをintに変換する。
   そして、片方の被演算数がlongなら、他方をlongに変換する。
 
  そして、ここでちょっと難しいのが、singnedとunsignedの扱い。特にこれらがCPUに
  依存するということになるので。興味のある型は、H8のC言語コンパイラのマニュアル
  などを調べてみてください。
 
  それから、変換は代入の時にも起きるということです。
  先に計算の結果は、高い型(広い型)の方になるということを説明しましたが、それを左
  辺の被演算数に代入する時にも、一処理があります。右辺の値が左辺の型に変換され、
  結果の型となります。次の例を考えてみてください。
 
   int i;
   char c;
   i = c; //(1)
   c = i; //(2)
 
  ここの結果は、cは不変であるということです。
  しかし、(1)と(2)の処理順序を逆にすると、情報が失われる可能性が出てきます。大きさ
  が異なる型の変数間の変換には注意しましょう。
  特に高い型(広い型)から低い型(狭い型)への変換では、高い型(広い型)の変数が取り得
  る値の範囲を有る程度正確に把握しておく必要があります。低い型(狭い型)の変数の値
  の範囲に入るというようなことです。
 
  また、浮動小数点数の型から整数型へ変換する時は、二つのことに注意が必要です。小
  数点より上の値は、それを受ける整数型の大きさと合う必要があります。shortでいい
  のか、longがいいのか、charであれば、尚更です。また、もう一つは、小数点以下の扱
  いです。小数点以下の処理がCPUやコンパイル結果の処理での扱いがどうなっているの
  によって、数値の扱いにおける精度の問題になることがあります。計測など、シビアな
  計算をする際には、要注意です。時折、小数点以下の値を整数型の変数へ引き継ぐ際、
  浮動小数点数を10倍にしたり、100倍にしたりして、桁上げ処理をする様な際、小数
  点部の精度が正しいかどうか、入念なテストをすることが求められる時もあるでしょう。
 
 
 ■キャスト
  変数の型を強制的に変換する為の仕組みが用意されています。
  これを使うことで、式(文)の中で扱われる型、精度を自分で制御することができるから
  です。「明示的な型変換」ということが言えるでしょう。これを「キャスト(cast)」と
  いいます。任意の式に適用=強制的な型変換をします。一般的な形式は次の通りです。
 
   (指定したい型)式
 
  この式(式(文)や変数、定数が扱われます)は、上記の変換規則に従って、指定の型名に
  変換されます。キャストの正確な意味は、式があたかも指定した型をもつ変数の様に代
  入されて、それが使われている文(式)の中で使われるということになります。
 
   例 int i;
     float f;
     f = (float)i;
 
  関数の引数の型変換について述べます。
  平方根を計算する関数sqrtというものを作ったとします。そして、次の様なプロトタイ
  プ宣言で、次の様になっているとします。
 
   double sqrt(double);
 
  整数型変数のiの平方根を求めたい時、iを強制的にdouble型へ変換する為、次の様な書
  き方をします。これは、前述のキャストを使っています。
 
   例 double rootResult;
     int i;
     rootResult =sqrt((double)i);
 
  只、前述の算術変換の様子からすると、
 
     rootResult =sqrt(i);
 
  としても、問題ないことが分かります。でもこれは、変換についても正しい知識があっ
  て、謂わば、分かって使っているということが大事で、何となく動いて、正しそうな値
  が取得できたので万事大丈夫と思っていると、後で大きな間違いの元になることがあり
  ます。C言語は、自動的に何でもかんでも、正しい処理となる様に動いてくれることは
  ないので、それこそプログラマの自己責任の上で、処理が組み立てられるのだというこ
  とを気にしておきましょう。
 
 
 ■変換:C言語の一般論から
  上記内容と重複することがありますが、「変換」についてC言語の一般論から述べます。
  H8のプログラム場面では、少し異なる様子があるかもしれません。特に変数の型では、
  そのC言語の仕様をよく検討しておくことが奨められます。一般論としては、CPUの大
  きさが大型計算機もその範囲に含めてきますからね。でも、その考え方、基本的な仕様
  は同じということありますから、H8でしっかり理解したC言語の使い方は、その後、パ
  ソコンや他の機種のCPUのプログラムをする機会があった時、そのまま使うことができ
  るということが言えます。
 
  式(文)の中で、演算子が処理の重要な役割を担いますが、この演算子の中には、被演算
  数(定数や変数)によって一つの型から、他の型への被演算数の値の変換を引き起こすも
  のがあります。まず、この理解が変換の第一歩です。式(文)を構成している被演算数の
  型が違う時、何となく誰かが型の変換をして、処理の便宜を図ってくれる(くれている)
  ・・ということではなく、その式(文)の処理の中核である”演算子”がこれを行うとい
  うことを覚えておいてください。
 
  ・整数への格上げ
   文字や短い整数(short int)或いは、整数のビット・フィールドは、符号付きも符号な
   しもすべて、整数が使える式の中で使って構いません。
   ということで、もし、元の型の全ての値がintで表せる時には、その値はintに変換さ
   れます。もれなく・・
   そうでない時には、値は、unsigned intに変換され、処理が続きます。
   これを「整数への格上げ」といいます。
 
  ・整数への変換
   一番分かりやすい変換です。でも、その仕組みはちょっとややこしくなっておりまし
   て、次のような内容が一般的なC言語の変換の仕様です。
   任意の整数は、その整数に適する最小の負でない値、すなわち符号なし型で表現する
   ことが可能な最大値より、モジュロ1だけ大きい値を見つけることによって、与えら
   れた符号なし型に変換されます。2の補数表現では、符号なし型のビット・パターン
   がより狭い時には、これは左側の切り捨てに等しく、逆に符号なし型の方が広い時に
   は、ゼロを詰めた符号なし値か、符号拡張による符号付き値と等しくなる様になりま
   す。
   ・・何だか分からないですね。というようなことが行われるということですね。これ
   は、忘れちゃってもいいです。ま、簡単に言うと・・
   任意の整数が符号付き型に変換される時、それが新しい型で表現される時には、その
   値は変わらない。そうでない時は、処理系により左右されるということになります。
   ・・ということに落ち着きます。
 
  ・整数と浮動小数点数
   浮動小数点型の値を整数型に変換する時には、小数点部分が無視されます。これが基
   本的な動きです。変換の結果、生じる値が整数型で表現できない時には、その値は、
   不定でよいとなっています。特に負の浮動小数の数値の符号なし整数への変換につい
   ては明確に決められていないとなっています。
   その逆の場合、つまり、整数型の値が浮動小数点数に変換する時はどうなるか。その
   値が表現可能な範囲にあるが、正確には表現できない時には、結果は次に高い、或い
   は、次に低い表現可能な値になります。その結果が範囲外の時には、その結果、取り
   得る値がどうなるかは不定です。
   この変換の時が一番面倒です。
   よくある問題は、浮動小数点の値:0.9999が整数型に変換された時、1になるのか、
   或いは、0になるのか。逆の場合、整数の値:1が浮動小数点へ変換された時、丁度
   1になるのか、1に近い1を超えた値なのか、1に近い1より小さい値になるのか、そ
   れは、CPU、コンパイラによってどうなるかを要チェックです。同じ値を使って、
   変換を繰り替えす:浮動小数点→整数→浮動小数点→整数・・をしていると違う値に
   なっていく・・ということが出てきたりします。
 
  ・浮動小数点型
   精度がより低い浮動小数点の値が、精度が同じ、或いはより高い浮動小数点型に変換
   される時には、その値は変わりません。型のサイズが大きい方に吸収される様なイメ
   ージでよいでしょう。
   また、より精度の高い浮動小数点の値が、より精度の低い浮動小数点型に変換され、
   その値が表現可能な範囲にあれば、その結果は次のより高い、或いは次のより低い表
   現可能値になります。それぞれの表現できる値の範囲内にあるか、あっても、その桁
   数がどうかというところがポイントです。特に、値の範囲に収まっていても、精度(
   桁数)高い→低い方へ変換される時、元の値と変換結果の値に差があるのかを充分な
   テストを通して、確認しておくことが重要でしょう。
   最後に、その結果の値が表現可能な範囲外の時には、そのふるまいは不定とされてい
   て、CPUやコンパイラの結果に依存しますから、ここも前記同様、十分なテストを通
   して、それでも問題がないのだということを確認することが大切です。
 
  ・算術変換
   この変換は、演算子で下記に示す様な型になっていきます。
   この変換の結果、被演算数を共通の型にすることであり、それは又、結果の型にもな
   ります。
   ------
   先ず、いずれかの被演算数がlong doubleなら、他方もlong doubleに変換されます。
   そうではなく、片方の被演算数がdoubleなら、他方もdoubleに変換されます。
   どうではない時は、両方の被演算数に対して整数への格上げが行われます(前述を参
   照のこと)。
   そして、片方の被演算数がunsigned long intなら、他方もunsigned intに変換されま
   す。
   そうではなく、片方の被演算数がlong intで、他方がunsigned intである時は、その
   効果はlong intがunsigned intのすべての値を表現しうるかどうかに左右されます。
   それが可能な時は、unsigned long intに変換されます。
   そうではなく、片方の被演算数がlong intの時には、他方もunsigned intに変換され
   ます。
   そうではなく、片方の被演算数がunsigned intであれば、他方もunsigned intに変換
   されます。
   そうではない時には、両方の被演算数は、型intをもつことになります。
   ------
   ここでちょっとだけ(複雑ついでに)、注意するところを述べると、符号なしの式を同
   じサイズの符号付きの式を比較する時には、予期しない結果がでることがあるとされ
   ています。ということで、基本的な流れや処理の優先度、結合法則があるにしても、
   型とサイズのところでは、CPUやコンパイラによって得られる数値や判定が微妙に異
   なる場合があるのだということを頭のどこかに置いておく必要があります。

ものづくりBLOG

Blog Category

Blog Calendar

RSS 2.0