4.2.5. C99 互換関数

上記の関数の他に、ARM では C99 規格で定義されている関数群もサポートされています。

これらの C99 互換関数は、戻り値を生成できるユーザ定義の例外トラップハンドラをインストールするための唯一のインタフェースです。 このセクションで説明する関数、型、およびマクロのすべては fenv.h 内で定義されています。

C99 では、fenv_tfexcept_t の 2 つのデータ型が定義されています。 C99 規格ではこれらの型に関する情報が指定されていないため、移植可能なコードを作成するには、これらの型を内部的に処理する必要があります。 ARM コンパイラでは、これらの型は構造型として定義されます。 詳細については、C99 インタフェースの ARM コンパイラ拡張を参照して下さい。

fenv_t 型は、現在の浮動小数点環境に関する以下のすべての情報を保持するように定義されています。

fexcept_t 型は、一連の例外に関する以下のすべての情報を保持するように定義されています。

C99 の丸めモードと例外のマクロ

C99 では、各丸めモードと各例外のマクロも定義されています。 マクロを以下に示します。

FE_DIVBYZERO
FE_INEXACT
FE_INVALID
FE_OVERFLOW
FE_UNDERFLOW
FE_ALL_EXCEPT
FE_DOWNWARD
FE_TONEAREST
FE_TOWARDZERO
FE_UPWARD

例外のマクロはビットフィールドに作用します。 マクロ FE_ALL_EXCEPT は、すべてのビットフィールドのビットごと論理和を実行します。

例外フラグの処理

C99 では、例外のクリア、テスト、および生成を行う、以下の 3 つの関数が定義されています。

void feclearexcept(int excepts);
int fetestexcept(int excepts);
void feraiseexcept(int excepts);

feclearexcept 関数は、指定された例外の sticky フラグをクリアします。 fetestexcept 関数は、指定された例外の sticky フラグのビットごと論理和を返します(したがって、オーバーフローフラグが設定されたが、アンダーフローフラグは設定されなかった場合、fetestexcept(FE_OVERFLOW|FE_UNDERFLOW) を呼び出すと FE_OVERFLOW が返されます)。

feraiseexcept 関数は、指定された例外を不特定な順序で生成します。 この方法で生成される例外のトラップが有効にされている場合は、この関数が呼び出されます。

C99 では、特定の関数に関するすべての項目の保存と復元を行う関数も定義されています。 これには、sticky フラグ、例外がトラップされるかどうかの情報、トラップハンドラのアドレスなどが含まれます。 これらの関数は以下のとおりです。

void fegetexceptflag(fexcept_t *flagp, int excepts);
void fesetexceptflag(const fexcept_t *flagp, int excepts);

fegetexceptflag 関数は、指定された例外に関連するすべての情報を、指定された fexcept_t 変数にコピーします。 fesetexceptflag 関数は、指定された例外に関連するすべての情報を、fexcept_t 変数から現在の浮動小数点環境にコピーします。

Note

fesetexceptflag を使用することで、トラップハンドラを呼び出すことなく、トラップされる例外の sticky フラグに 1 を設定できます。一方、feraiseexcept は、トラップされるすべての例外のトラップハンドラを呼び出します。

丸めモードの処理

C99 では、丸めモードを制御する以下の 2 つの関数が定義されています。

int fegetround(void);
int fesetround(int round);

fegetround 関数は、C99 の丸めモードと例外のマクロに示すマクロの 1 つと同じ値を持つ、現在の丸めモードを返します。 fesetround 関数は、現在の丸めモードに、指定された値を設定します。正しい値が設定されると fesetround によってゼロが返され、その引数が無効な丸めモードである場合はゼロ以外の値が返されます。

環境全体の保存

C99 では、浮動小数点環境全体の保存と復元を行うために以下の関数が提供されています。

void fegetenv(fenv_t *envp);
void fesetenv(const fenv_t *envp);

fegetenv 関数は、浮動小数点環境の現在の状態を、指定された fenv_t 変数に保存します。 fesetenv 関数は、指定された変数から環境の状態を復元します。

fesetexceptflag と同様に、fesetenv はトラップされた例外の sticky フラグを設定するときに、トラップハンドラを呼び出しません。

例外の一時無効化

C99 では、例外が発生しそうなコードを実行するときに、例外がトラップされるのを回避するために以下の 2 つの関数が提供されています。 これらの関数は、トラップされた例外で ARM のデフォルトの動作を使用する場合などに便利です。 デフォルトでは、SIGFPE が生成され、アプリケーションが終了します。

int feholdexcept(fenv_t *envp);
void feupdateenv(const fenv_t *envp);

feholdexcept 関数は、指定された fenv_t 変数に現在の浮動小数点環境を保存し、すべての例外のトラップを無効に設定し、すべての例外の sticky フラグをクリアします。 ユーザは次に、不都合な例外が発生しそうなコードを実行し、それらの例外の sticky フラグがクリアされていることを確認できます。 次に feupdateenv を呼び出します。 これによって例外トラップが復元され、必要に応じて呼び出されます。

例えば、frob() 関数によって、アンダーフロー例外または無効演算例外が発生する可能性があるとします(いずれの例外もトラップされると仮定します)。 アンダーフロー例外は無視し、無効演算が試行されたかどうかだけを確認するには、 以下のように記述します。

fenv_t env;
feholdexcept(&env);
frob();
feclearexcept(FE_UNDERFLOW);
feupdateenv(&env);

これにより、frob() 関数によってアンダーフローが発生しても、そのアンダーフローは feclearexcept によって再びクリアされるため、feupdateenv が呼び出されてもトラップは発生しません。 ただし、frob() によって無効演算例外が発生した場合には、feupdateenv が呼び出されたときに sticky フラグが設定されるため、トラップハンドラが呼び出されます。

このメカニズムが C99 で提供されている理由は、C99 では個々の例外について例外トラップを変更する方法が指定されていないためです。 より効果的な方法に、無効演算トラップを有効にしたまま、__ieee_status を使用してアンダーフロートラップを無効にする方法があります。 この方法には、無効演算トラップハンドラに、無効演算に関するすべての情報(どの演算が、どのデータに対して実行されたかという情報)が渡されるため、その演算の結果を生成できるという利点があります。 C99 の方法では、無効演算トラップハンドラは事後に呼び出され、例外の原因に関する情報も渡されず、代用できる結果を返すには呼び出されるのが遅すぎるなどの欠点があります。

Copyright © 2007 ARM Limited. All rights reserved.ARM DUI 0349AJ
Non-Confidential