Everything
11.10 C++言語(EC++含む)でmath.hの一部関数(frexp、ldexp、scalbnおよびremquo)
を使用する場合 の制限事項

C++/EC++コンパイル時に、math.hの一部の関数(frexp、ldexp、scalbn、remquo)の実引数をint型にすると、実行時に無限ループとなるオブジェクトが生成されます。

発生条件:

次の条件(1)(2)を全て満たす場合が該当します。

(1)

C++ソース(拡張子が.cpp)または、-lang=cppオプションが有効である。

(2)

math.hをインクルードして、以下の関数をそれぞれの条件で呼び出している。

(a)

frexp(double, long *) の第2引数の値を (int *)型とする

ただし、第1引数がfloat型で、-dbl_size=8オプション指定時を除く

(b)

ldexp(double, long) の第2引数の値をint型とする

ただし、第1引数がfloat型で、-dbl_size=8オプション指定時を除く

(c)

scalbn(double, long) の第2引数の値をint型とする

ただし、第1引数がfloat型で、-dbl_size=8オプション指定時を除く

(d)

remquo(double, double, long *) の第3引数の値を (int *)型とする

ただし、第1または第2引数がfloat型で、-dbl_size=8オプション指定時を除く

 

発生例:

[file.cpp]

  // C++ソースとしてコンパイルした場合に無限ループになる例
  #include <math.h>
  double d1,d2;
  int i;
  void func(void)
  {
    d2 = frexp(d1, &i);
  }

 

[コマンドライン例]

ccrx -cpu=rx600 -output=src file.cpp

 

[file.src] ソース出力例

  _func:
    ; ...(中略)
    BSR __$frexp__tm__2_f__FZ1ZPi_Q2_21_Real_type__tm__4_Z1Z5_Type ; frexpの代替関数を呼ぶ
    ; ...(中略)
  __$frexp__tm__2_f__FZ1ZPi_Q2_21_Real_type__tm__4_Z1Z5_Type:
  L11:
    BRA L11 ; 再帰呼び出しとなってしまう

 

回避策:

次のいずれかの方法で回避できます。

(1)

-lang=cまたは-lang=c99を指定し、C言語としてコンパイルする。

(2)

引数のintおよびint*をlongおよびlong*に変更する。

(3)

math.hの後に、使用する関数ごとに定義を追加する。

      /* frexp関数の場合 */
      static inline double frexp(double x, int *y)
      { long v = *y; double d = frexp(x,&v); *y = v; return (d); }
      /* ldexp関数の場合 */
      static inline double ldexp(double x, int y)
      { long v = y; double d = ldexp(x,v); return (d); }
      /* scalbn関数の場合 */
      static inline double scalbn(double x, int y)
      { long v = y; double d = scalbn(x,v); return (d); }
      /* remquo関数の場合 */
      static inline double remquo(double x, double y, int *z)
      { long v = *z; double d = remquo(x,y,&v); *z = v; return (d); }

 

回避策(2)の例

[file.cpp] の変更例

  #include <math.h>
  double d1,d2;
  int i;
  void func(void)
  {
    long x = i; /* 一旦long型変数で受ける */
    d2 = frexp(d1, &x); /* long型変数で呼び出し */
    i = x; /* i に値を設定 */
  }

 

回避策(3)の例

[file.cpp] の変更例

  #include <math.h>
  /* 宣言を追加 */
  static inline double frexp(double x, int *y)
  { long v = *y; double d = frexp(x,&v); *y = v; return (d); }
  double d1,d2;
  int i;
  void func(void)
  {
    d2 = frexp(d1, &i);
  }