前のセクションでは、ieee_handler を使用した例を示しました。通常、ieee_handler または sigfpe のどちらを使用するかを選択する場合は、前者をお勧めします。
整数演算例外をトラップする場合などに、ハンドラとして sigfpe を使用することがあります。使用例 23 では、SPARC ベースのシステムで整数のゼロ除算をトラップしています。
使用例 23 整数例外のトラップ/* Generate the integer division by zero exception */
#include <signal.h>
#include <siginfo.h>
#include <ucontext.h>
void int_handler(int sig, siginfo_t *sip, ucontext_t *uap);
int main() {
int a, b, c;
/*
* Use sigfpe(3) to establish "int_handler" as the signal handler
* to use on integer division by zero
*/
/*
* Integer division-by-zero aborts unless a signal
* handler for integer division by zero is set up
*/
sigfpe(FPE_INTDIV, int_handler);
a = 4;
b = 0;
c = a / b;
printf("%d / %d = %d\n\n", a, b, c);
return 0;
}
void int_handler(int sig, siginfo_t *sip, ucontext_t *uap) {
printf("Signal %d, code %d, at addr %x\n",
sig, sip->si_code, sip->__data.__fault.__addr);
/*
* automatically for floating-point exceptions but not for
* integer division by zero.
*/
uap->uc_mcontext.gregs[REG_PC] =
uap->uc_mcontext.gregs[REG_nPC];
}
次に、 Fortran のサブルーチンを呼び出す C ドライバの簡単な例を示します。C および Fortran の操作の詳細は、Oracle Developer Studio 12.5: C ユーザーズガイドおよびOracle Developer Studio 12.5: Fortran ユーザーズガイドを参照してください。C ドライバを次に示します (driver.c というファイルに保存します)。
使用例 24 C からの Fortran の呼び出し/*
* a demo program that shows:
* 1. how to call f95 subroutine from C, passing an array argument
* 2. how to call single precision f95 function from C
* 3. how to call double precision f95 function from C
*/
extern int demo_one_(double *);
extern float demo_two_(float *);
extern double demo_three_(double *);
int main()
{
double array[3][4];
float f, g;
double x, y;
int i, j;
for (i = 0; i < 3; i++)
for (j = 0; j < 4; j++)
array[i][j] = i + 2*j;
g = 1.5;
y = g;
/* pass an array to a fortran function (print the array) */
demo_one_(&array[0][0]);
printf(" from the driver\n");
for (i = 0; i < 3; i++) {
for (j = 0; j < 4; j++)
printf(" array[%d][%d] = %e\n",
i, j, array[i][j]);
printf("\n");
}
/* call a single precision fortran function */
f = demo_two_(&g);
printf(
" f = sin(g) from a single precision fortran function\n");
printf(" f, g: %8.7e, %8.7e\n", f, g);
printf("\n");
/* call a double precision fortran function */
x = demo_three_(&y);
printf(
" x = sin(y) from a double precision fortran function\n");
printf(" x, y: %18.17e, %18.17e\n", x, y);
ieee_retrospective_();
return 0;
}
drivee.f というファイルに Fortran のサブルーチンを保存します。
subroutine demo_one(array) double precision array(4,3) print *, 'from the fortran routine:' do 10 i =1,4 do 20 j = 1,3 print *, ' array[', i, '][', j, '] = ', array(i,j) 20 continue print * 10 continue return end real function demo_two(number) real number demo_two = sin(number) return end double precision function demo_three(number) double precision number demo_three = sin(number) return end
コンパイルとリンクを行います。
cc -c driver.c f95 -c drivee.f demo_one: demo_two: demo_three: f95 -o driver driver.o drivee.o
出力は次のようになります。
from the fortran routine:
array[ 1 ][ 1 ] = 0.0E+0
array[ 1 ][ 2 ] = 1.0
array[ 1 ][ 3 ] = 2.0
array[ 2 ][ 1 ] = 2.0
array[ 2 ][ 2 ] = 3.0
array[ 2 ][ 3 ] = 4.0
array[ 3 ][ 1 ] = 4.0
array[ 3 ][ 2 ] = 5.0
array[ 3 ][ 3 ] = 6.0
array[ 4 ][ 1 ] = 6.0
array[ 4 ][ 2 ] = 7.0
array[ 4 ][ 3 ] = 8.0
from the driver
array[0][0] = 0.000000e+00
array[0][1] = 2.000000e+00
array[0][2] = 4.000000e+00
array[0][3] = 6.000000e+00
array[1][0] = 1.000000e+00
array[1][1] = 3.000000e+00
array[1][2] = 5.000000e+00
array[1][3] = 7.000000e+00
array[2][0] = 2.000000e+00
array[2][1] = 4.000000e+00
array[2][2] = 6.000000e+00
array[2][3] = 8.000000e+00
f = sin(g) from a single precision fortran function
f, g: 9.9749500e-01, 1.5000000e+00
x = sin(y) from a double precision fortran function
x, y: 9.97494986604054446e-01, 1.50000000000000000e+00
次の表は、SPARC アーキテクチャーのデバッグコマンドの例を示しています。
|
浮動小数点数を表示する場合、レジスタのサイズは 32 ビットであり、1 つの単精度浮動小数点数は 32 ビットを占有すること (つまり、1 つのレジスタに収まります)、倍精度浮動小数点数は 64 ビットを占有する (つまり、1 つの倍精度数を保持するには 2 つのレジスタが使用されます) に留意してください。16 進数表現では、32 ビットは 8 桁の 16 進数に相当します。adb を使用して FPU レジスタを表示したスナップショットでは、表示は次のような形式になります。
<fpu レジスタ名> <IEEE 16 進数の値> <単精度> <倍精度>
3 番目の列には、2 番目の列に表示されている 16 進数を単精度の 10 進数に変換した値が示されます。4 番目の列は、レジスタのペアを解釈しています。たとえば、f11 の行の 4 番目の列は、f10 および f11 を 64 ビットの IEEE 倍精度数として解釈しています。
f10 および f11 は 1 つの倍精度値の保持に使用されているため、その値の最初の 32 ビットの (f10 行の) 7ff00000 が +NaN として解釈されても無意味になります。64 ビット全体 7ff00000 00000000 の解釈である +Infinity は、意味のある解釈になっています。
最初の 16 個の浮動小数点データレジスタの表示に使用されている adb コマンド $x は、 fsr (浮動小数点ステータスレジスタ) も表示します。
$x fsr 40020 f0 400921fb +2.1426990e+00 f1 54442d18 +3.3702806e+12 +3.1415926535897931e+00 f2 2 +2.8025969e-45 f3 0 +0.0000000e+00 +4.2439915819305446e-314 f4 40000000 +2.0000000e+00 f5 0 +0.0000000e+00 +2.0000000000000000e+00 f6 3de0b460 +1.0971904e-01 f7 0 +0.0000000e+00 +1.2154188766544394e-10 f8 3de0b460 +1.0971904e-01 f9 0 +0.0000000e+00 +1.2154188766544394e-10 f10 7ff00000 +NaN f11 0 +0.0000000e+00 +Infinity f12 ffffffff -NaN f13 ffffffff -NaN -NaN f14 ffffffff -NaN f15 ffffffff -NaN -NaN
次の表は、x86 アーキテクチャーのデバッグコマンドの例を示しています。
|
次の例は、adb のルーチン myfunction に対応するコードの先頭にブレークポイントを設定する 2 つの方法を示しています。最初に次のコマンドを使用できます。
myfunction:b
次に、myfunction に対応するコードの先頭に対応する絶対アドレスを判別して、その絶対アドレスにブレークを設定できます。
myfunction=X 23a8 23a8:b
f95 を指定してコンパイルされた Fortran プログラムのメインサブルーチンは、 adb への MAIN_ と認識されています。adb の MAIN_ にブレークポイントを設定するには、次のコマンドを実行します。
MAIN_:b
浮動小数点レジスタの内容を検査する場合、dbx コマンドの regs –F で表示される 16 進数値は、数値の 10 進数表現ではなく base-16 表現です。SPARC ベースシステムでは、adb コマンドの $x および $X は、16 進数表現および 10 進数値の両方を表示します。x86 ベースシステムでは、adb コマンドの $x は 10 進数値のみを表示します。SPARC ベースシステムでは、倍精度値の場合、奇数レジスタの横に 10 進数値が表示されます。
オペレーティングシステムではプロセスが最初に使用するまで浮動小数点ユニットが無効にされるため、デバッグしているプログラムがアクセスするまで、浮動小数点レジスタを変更できません。
x86 での対応する出力は次のようになります。
$x 80387 chip is present. cw 0x137f sw 0x3920 cssel 0x17 ipoff 0x2d93 datasel 0x1f dataoff 0x5740 st[0] +3.24999988079071044921875 e-1 VALID st[1] +5.6539133243479549034419688 e73 EMPTY st[2] +2.0000000000000008881784197 EMPTY st[3] +1.8073218308070440556016047 e-1 EMPTY st[4] +7.9180300235748291015625 e-1 EMPTY st[5] +4.201639036693904927233234 e-13 EMPTY st[6] +4.201639036693904927233234 e-13 EMPTY st[7] +2.7224999213218694649185636 EMPTY