トリッキーコードネット トップへ戻る   C/C++, Java, Perl, PHP, JavaScript, アルゴリズム, ショートコーディング, IOCCCコードの解説, 等々

サイト情報

トリッキーなコード

7行プログラミング

物凄いコード集

アルゴリズム

データ構造

C/C++な話題

コードサンプル

ツール/環境構築

開発ノウハウ 等

ネタ/ジョーク集

おススメ書籍/サイト

サイトTOP >> 開発ノウハウ 等 >> 3.コンパイラ言語のデータ型処理に対する認識不足編

3.コンパイラ言語のデータ型処理に対する認識不足編

バグが発生しやすい王道パターン - 2.言語に対する理解不足編の続きです。

プログラミングにおいて、『 こういった時(こういった箇所)でバグが発生しやすいぞ~ 』というのを纏めてみました ^^;)
(※あくまで管理人の独断と偏見、それに、少々の経験に基づいたものですのであしからず)

3-1. 異なる型への代入によるデータの維持・消滅

 1 : #include <stdio.h>
 2 :
 3 : int main(void)
 4 : {
 5 :     int   i, j;
 6 :     float f1, f2, f3;
 7 :
 8 :     i  = 100;
 9 :     j  = 30;
10 :
11 :     f1 = i / j;
12 :     f2 = (float)(i / j);
13 :     f3 = (float)i / j;;
14 :
15 :     printf("%f\n", f1);
16 :     printf("%f\n", f2);
17 :     printf("%f\n", f3);
18 :
19 :     return 0;
20 : }
int型変数i, jのそれぞれに100と30を代入し、i ÷ j の 結果をfloat型変数に代入、その結果を表示するというプログラムです。 実行結果は以下の通り C言語の暗黙の型変換について 11行目と12行目の代入では、int型 ÷ int型 の演算結果をfloat型にキャスティングし、float型変数に代入しています。 そのため、キャスティング以前に少数点情報が消滅している為、結果が 3.000... と表示されます。 13行目の代入では、float型(int型をキャスティング) ÷ int型 の演算結果を、float型変数に代入しています。 float型 ÷ int型の演算は、演算時にfloat型 ÷ float型 に自動で型拡張する為、結果はfloat型となり、小数点情報が消滅しません。 ・・・この「演算結果の小数点情報の維持 or 消滅」が、プログラマーの意図とは異なる場合、 致命的なバグが発生することは想像に難くありません。 さらに、最近のコンパイラは性能が良い為、異なるデータ型変数への代入によってデータが喪失する可能性がある場合、警告を出してくれます。 (上記コードでは、11行目に警告がでます。← VC++2010の場合) しかし、同様に小数点情報が消滅している12行目では、警告がでません。

3-2. 桁あふれ(オーバーフロー)

 1 : #include <stdio.h>
 2 :
 3 : int main(void)
 4 : {
 5 :     short i, s, res;
 6 :
 7 :     for (i = 0, s = 1; i <= 18; i++) {
 8 :         res = s << i;
 9 :         printf("%6d %6d\n", s << i, res);
10 :     }
11 :
12 :     return 0;
13 : }
short型変数sに1を代入し、0回 ~ 18回シフト演算させ、その結果を表示しています。 実行結果は以下の通り C言語の桁あふれ(オーバーフロー) 2010年現在、C言語にてshort型は16bitで構成されている為、変数に最大16回シフト演算を行うと、 桁あふれ(オーバーフロー)が発生し、値が0になります。 また、最上位bitは符号を表すbitの為、1 << 15で、short型変数に格納できる最小の数(-32768)が出現します。 しかし、一旦別変数に値を代入せず、printf()関数でダイレクトに値を表示する場合は、 int型として処理されてしまうので注意が必要です。 (※ C++の cout << (s << i) << endl;でも同様)

3-3. 目に見えない、変数の有効桁範囲

#include <stdio.h>

int main(void)
{
    float f1 = 0.333333;
    float f2 = 1.0;
    f2 /= 3;

    printf("%f %f\n", f1, f1 * 3);
    printf("%f %f\n", f2, f2 * 3);

    return 0;
}
float型整数に1.0を代入し、÷3 の後に ×3 を行った結果を表示しています。 実行結果は以下の通り C言語-目に見えない、変数の有効範囲 printf()で表示した場合、変数f1, f2共に「0.999999」が表示されますが、 1.0÷3を行ったf2の方は、×3をすると「1.000000」が表示されます。(← VC++2010の場合) この挙動はコンパイラ別に異なり、1.0 / 3 * 3 が 0.999999と計算されるものもあれば、 VC++2010の様に1.000000と計算されるものもあります。 コンパイラ別の仕様をよく理解していないと、コードの移植時に予期せぬバグに悩まされそうです。
バグが発生しやすい王道パターン - 4.インタプリタ言語のデータ型処理に対する認識不足編へ続く
         このエントリーをはてなブックマークに追加   


作業効率化・ライフハックのオススメ記事




コンピュータ・テクノロジーのオススメ記事





恋愛・人間関係のオススメ記事




※ 当サイトは、トップページからリンクで辿る事の出来るページに限り、リンクフリーです。
※ 当サイトの閲覧/利用によって生じた如何なる損害も、当サイト管理人は責任を負いません。
※ 当サイトの内容を転載される場合は、当サイトへのリンクをお願い致します。