• 検索結果がありません。

実行時エラー

ドキュメント内 note.dvi (ページ 185-193)

6.22 落ち穂拾い

6.22.3 実行時エラー

Cで作成したプログラムなどを実行する際に, Segmentation fault

Bus error

Floating exception

などというエラーが発生することがある.

6.22.3.1 Segmentation fault

Segmentation fault というエラーは,以下のように割り当てられていないメモリ領域に対するアクセ

スがあった場合に,「アクセス違反」として発生する.

/* Segmentation fault を起こす

* 意味:非割り当てメモリへのアクセス.

*/

#include <stdlib.h>

#include <stdio.h>

int main(int argc, char **argv) {

struct data { char x ;

struct data *next ; } *data_p, *p ;

data_p = (struct data *)malloc(sizeof(struct data)) ; data_p->x = ’1’ ;

p = data_p ;

printf("%c\n",p->x);

p = p->next ;

printf("%c\n",p->x);

/* ここで割り当てられていないメモリにアクセスしている */

return 0 ; }

6.22.3.2 Bus error

Bus errorというエラーは,以下のように,ワード境界に合わせられていないアドレスから,ワード単位

で読み取りを行おうとした場合などに発生する.

/* Bus error を起こす

* 意味:適切に境界を合わせていないアドレスからデータを読み取ろうとした.

* 原因:

* ハーフワード, ワード, ダブルワードの境界に合わせられていないアドレスから,

* それぞれ2バイト, 4バイト, 8バイトを読み取った.

*/

#include <stdlib.h>

int main(int argc, char **argv) {

char *s = "hello world" ; int *i = (int *)&s[1] ; int j ;

j = *i ; return 0 ; }

6.22.3.3 Floating exception

Floating exception エラーは,0での除算を行おうとすると発生する.

/* 0 で除算を行う. */

#include <stdio.h>

int main(int argc, char **argv) {

printf("%d\n",1/0) ; return 0 ;

}

これの代りに

printf("%f\n",1.0/0.0) ;

とすると,Infという答えが返ってくる.

6.22.3.4 実行時エラーのトラップ

UNIX では上のような実行時エラーはカーネルによって検出され,カーネルからプロセスに対してシグ

ナル(signal)を送ることによって,プロセスはエラーの発生を知ることが出来る. Cでは,標準ライブラ

リ関数signalを利用することによって,受け取ったシグナルの種類ごとにそのハンドラ (handler)を記

述することが可能になっている. 上のそれぞれの実行時エラーに対して, プロセスが受け取るシグナルは,

segmentation fault に対してはSIGSEGV,

bus errorに対してはSIGBUS,

floating exception に対してはSIGFPE と定められている105. したがって,

/* 0 で除算を行う.

実行時エラーをトラップする */

#include <stdio.h>

#include <signal.h>

extern int signal_handler(void) ; int main(int argc, char **argv) {

signal(SIGFPE, (void (*)(int))signal_handler) ; printf("%d\n",1/0) ;

return 0 ; }

int signal_handler(void) {

fprintf(stderr,"Floating exception が発生したので, 実行を停止します\n") ; exit(-1) ;

return ; }

として,ハンドラを記述すれば,実行時エラーに対して,適切な処理を行うことも可能である.

6.22.4 ライブラリ呼出しとシステムコール

これまでに各種の標準関数を利用してきたが, それらのほとんどはライブラリ関数の呼出しという手順 で行われていた. これに良く似た概念でシステムコールと呼ばれるものがUNIX上では存在する106. 例え ば,ファイルをオープンする関数としてfopenがあるが,この関数内では実際にはシステムコールopenが 用いられている. また, C のプログラム内からファイルを削除するためには, unlinkシステムコールが用 いられる.

このように, Cのプログラム内から呼び出すことが出来る関数として,ライブラリコールとシステムコー ルの2種類があることがわかる. ここでは,この2つの違いを簡単にまとめておこう.

ライブラリコールは ANSI規格で定められ,すべての処理系でその呼出し方法は同一であるが,シス テムコールは, OSによって異なる呼出し方法が異なる.

ライブラリコールは,ライブラリ内にあるサブルーチンの呼出しであるが,システムコールは,サービ スを受けるためのカーネル呼出しである.

ライブラリコールは,プロセスのアドレス空間で実行されるが,システムコールは,カーネルの空間で 実行される.

時間測定では,ライブラリコールは,「ユーザ」時間になるが,システムコールは,「システム」時間 になる.

105これらのシンボルはsignal.h内で定義される整数定数である.

106MS-DOSでは,これに相当するのはBIOSコールと呼ばれるものがある.

ライブラリコールは呼出しに時間が掛らないが,システムコールは,呼出しのオーバヘッドが大きい.

このように,一見似ているが,ライブラリコールとシステムコールはその役割が異なり, 処理系に依存する システムコールの部分を,ライブラリ関数によって吸収するという意味がある.

6.22.5 ANSI で定められた翻訳の最低基準

最後に, ANSIで定められた, 処理系に求められている最低基準を列挙しておこう. これらに挙げる数値 は翻訳限界と呼ばれ,「各限界の出現をそれぞれ少なくとも一つ含むプログラムのうち少なくとも一つを翻 訳および実行できなければならない」と定められている.

複合文, 繰り返し制御構造および選択制御構造に対する入れ子のレベル数(15)

条件付き取り込みにおける入れ子のレベル数 (15)

一つの宣言中の一つの算術型,構造体型,共用体型または不完全型を修飾するポインタ,配列および関 数宣言子(の任意の組み合わせ)の個数(12)

一つの完全宣言子における括弧に囲まれた宣言子の入れ子のレベル数(21)

一つの完全式における括弧に囲まれた式の入れ子のレベル数 (32)

内部識別子またはマクロ名において意味のある先頭の文字数 (31)

外部識別子において意味のある先頭の文字数 (6)

一つの翻訳単位における外部識別子数 (511)

一つのブロックにおけるブロック有効範囲を持つ識別子数(127)

一つの翻訳単位中で同時に定義されうるマクロ識別子数 (1024)

一つの関数定義における仮引数の個数 (31)

一つの関数呼出しにおける実引数の個数(31)

一つのマクロ定義における仮引数の個数(31)

一つのマクロ呼出しにおける仮引数の個数 (31)

一つの論理ソース行における文字数(509)

(連結後の)単純文字列リテラルまたはワイド文字列リテラル中における文字数(509)

(ホスト環境の場合)一つのオブジェクトのバイト数(32767)

#includeで取り込まれるファイルの入れ子のレベル数(8)

一つの switch文(入れ子になったswitch文を除く)中におけるcase名札の個数(257)

一つの構造体または共用体のメンバ数 (127)

一つの列挙体における列挙定数の個数 (127)

一つのメンバ宣言並びにおける構造体または共用体定義の入れ子のレベル数(15)

これらの翻訳限界を越えたプログラムは,必ずしも他の処理系で翻訳できるとは限らないことに注意しよう.

また,標準ヘッダファイルlimits.hには,各算術型で格納できる限界の数が書かれている. ここでは,そ のマクロ名と, ANSI規格に定められた最低限の数値を書いておく.

ビットフィールドでない最小のオブジェクト(バイト)におけるビット数 CHAR_BIT 8

signed char のオブジェクトにおける最小値 SCHAR_MIN -127

signed char のオブジェクトにおける最大値 SCHAR_MAX +127

unsigned charのオブジェクトにおける最大値 UCHAR_MIN 255

char のオブジェクトにおける最小値と最大値

CHAR_MIN CHAR_MAX

char のオブジェクトの値を符号付き整数として扱う場合,CHAR MINの値は,SCHAR MINと同じであ り,CHAR MAXの値は,SCHAR MAXと同じでなければならない.

その他の場合, CHAR MINの値は 0でなければならず,CHAR MAXの値は UCHAR MAX と同じでなけれ ばならない.

サポートするロケールに体する多バイト文字の最大バイト数 MB_LEN_MAX 1

short intのオブジェクトにおける最小値 SHRT_MIN -32767

short intのオブジェクトにおける最大値 SHRT_MAX +32767

unsigned short int のオブジェクトにおける最大値 USHRT_MAX 65535

intのオブジェクトにおける最小値 INT_MIN -32767

intのオブジェクトにおける最大値 INT_MAX +32767

unsigned intのオブジェクトにおける最大値 UINT_MAX 65535

long intのオブジェクトにおける最小値 LONG_MIN -2147483647

long intのオブジェクトにおける最大値 LONG_MAX +2147483647

unsigned long int のオブジェクトにおける最大値 LONG_MAX 4294967295

この他にもANSI規格にはfloat.h内で定める,浮動小数点型の特性も定められている.

ドキュメント内 note.dvi (ページ 185-193)