mo うが扱いが楽て、あるといわれるが , 残念な がら C の仕様はそうて、はない C て、は浮動小数と整数の間の型変換に関し ても , 明示的に指示しなくても行われるこ とがある。これはたとえば Pascal などとは 明らかに異なるルールて、ある。 PascaI て、は 整数から浮動小数への変換は暗黙のうちに 行われることがあるが , 逆は明示的に型変換 関数を用いないかぎり行われない。浮動小 数から整数への変換というのは情報が失わ れる方向への変換なのて、 , 明示的に指示さ れた場合以外は行わないほうが安全て、ある , というのがその理由て、ある。 一方 , C て、は浮動小数の値を整数の変数に 演算子十には次の制約がある (ANSI 3.3. というルールになった。 C て、は Fortran66 並 代入するときや , 整数型の関数の return 文の みに , 代入と return てしか暗黙の変換が起き オペランドに浮動小数型の式が記されてい 加算 ( 十 ) の場合 , 両方のオペランドが ないとしている。これはひょっとすると , る場合などて、は暗黙の型変換が行われる。 ともに算術型であるか , C が設計されたときには Fortran66 の時代だ その場合には前述のように小数部分が切り ったことと関係があるのかもしれないが , 捨てられて整数に変換されるのて、ある。あ あるいは , 一方のオペランドがオプジェクトへの 比較的穏健なルールといえる。 えて危険な暗黙の型変換を許しているのは , C というのがプログラマの記述を尊重すると ポインタであり , 異なるサイズ浮動小数間の変換 他方が汎整数型である。 いう基本姿勢て、設計された言語だからだろ ・すなわち , 一方がオプジェクトへのポイ う。ただし , C といえども , いかなる場合に ンタである場合には他方は整数型 (integr ANSIC て、は浮動小数型として 3 種類用意 おいても浮動小数を整数へと型変換すると している。 float, double, および long dou (l) でなければならない。 いうわけて、はない。たとえば List 3 を見てほ ble て、ある。これらの浮動小数型間て、の型変 ・先の式で , a は配列名であるので , ポイン しい 換も起こり得る。ただし , それらの間のル タ生成によってこれはポインタとなる。 このプログラムて、は配列の添字に double ールは単純てある。まずサイズが増える方 ・したがって , x は汎整数型の式でなければ の変数 , すなわち浮動小数型の式を用いて ならない。ところが実際には x は doub 厄で 向 (float → double, float → long double, お いる。これは ANSI 違反てあり , ANSI に忠 よび double → long double) への変換の場合 , あるのでエラーとなる。 実な処理系て、はコンパイルエラーになるは その値は変化しないとされる。 ほかにも switch 文の式や if 文の式 , while ずて、ある。手元の処理系ては Turb 。 C 十十 一方 , サイズが減る方向 (double → float, 文や f 。 r 文のループの継続条件の式など , い Ver. 1.01 は拡張されているらしく , コンパ long double → double, および long double わゆるスカラー型の式を要求する場面て、は イルが正常に終了してしまったが , MS ー CV → float ) の場合には , ふたつの問題がある。 浮動小数型の式を書くことはて、きない er. 6.0 や LSI C ー 86 Ver. 3.3 て、は ANSI どお すなわち , かの言語の例ては , たとえば FORTRAN の りにエラーになった。 場合 , Fortran66 の時代には代入以外て、の浮 ①変換後の値が表現不可能である場合 以下の理由によりエラーになる。 この場合には結果は不定となっている。 ・ a [x] は , 定義によって * ( a + ( x ) ) と等 動小数→整数への型変換を許していなかっ ②変換後の値を正確に表現することが不 たが , Fortran77 になったときに型変換に関 しい。 可能な場合 するルールを大幅に緩和するとともに , あ ・冗長なカッコを省くと , これは * ( a 十 x ) りとあらゆるところて、必要に応じて暗黙の この場合には , 結果はその値よりも大き である。 , こで a 十 x という演算があるが , 実は 2 項 型変換が起きて浮動小数を整数に変換する くてもっとも近い値 , あるいは小さくても 配列の添字に doub 厄を使う ( ANSI 違反の例 ) List #include く stdio. h> int main(void) double x; int a [ 10 ] ; for (x = 0.0 : x く 10.0 ; x + = 1. の aCx] return 0 ; ANSI C ー more 147
List 33 グラムを記述していきます。 Windows の 場合 , あらかじめスケルトンを用意して おくとたいへん便利て、す ( List 33 ~ 35 ) 。 ・リソースファイルの作成 / 修正 ファイルを保存した後 , 再び新規ファイ ルを作成してリソース定義ファイルを記 述します (List 36 ) 。 ・プログラムのコンバイル & リンク Project メニューから Build を選択して , コ ンパイルを開始します。もし , コンパイ ルエラーが発生した場合には , プログラ ムの作成 / 修正以降を繰り返します ( List 3 ・プログラムの実行 MS-DOS の場合は Run メニューから Exec ute を選択して , プログラムを実行させま す。 Windows プログラムの場合には , p WB の起動のさせかたによって手順が変わ ります。 Windows から起動した場合 WX サー バが常駐しているかを確認します。常 駐していない場合には一十亘て、 Windows 環境下へ移動し , WX サーバ を常駐させます。 Run メニューから Ex ecute を選択します。 Windows 環境下て、 PWB を起動すると , この機能が利用て、きるのて、 Windows プ ログラムを作成する場合には , コマン ドラインから PWB を起動するよりも便 利て、す。 DOS プロンプトから起動した場合 PW B を抜けて Windows を起動し , プログ ラムを実行させます。 もしバグが発生して , デバッグを行いた い場合は , 次へ進みます。 ・デバッグ準備 CodeView デバッグが必要になった場合 , Options メニューから Build Options を選 択し , BuiId Options ダイアログを表示さ せます。ダイアログにある Debug Optio ns を選択します。 ・再コン / ヾイル Project メニューから Rebuild A11 を選択し 80 C MAGAZINE 1992 12 52 : BOOL 53 : lnitlnstance (HANDLE hlnstance, int nCndShow) 54 : { 55 : HWND hWnd; 56 : 57 : hlnst = hlnstance; 58 : hWnd = CreateWindow ( 59 : ” GenericWClass ” 60 : "Generic アフ。リケーン” , / / キャプション名 61 : 62 : WS_OVERLAPPEDWINDOW, CW_US EDEFAULT, / * デフォルト水平位置 * / 64 : CW_USEDEFAULT, / * デフォルト垂直位置 * / 65 : CW_USEDEFAULT, / * デフォルト福 66 : CW_USEDEFAULT, / * デフォルト高さ NULL, 68 : NULL, 69 : hlns tance, NULL) ; 70 : 71 : if (!hWnd) 72 : 73 : return FALSE ; 74 : ShowWindow (hWnd, nCmdShow) ; UpdateWindow (hWnd); 77 : return TRUE; 78 : } List 34 ー ウインドウの処理部分 1 : #include く windows. h> 2 : 3 : #include ” generic. h ” 4 : 5 : extern HANDLE hlnst; 6 : 7 : 10 FAR PASCAL 8 : MainWndProc (HWND hWnd, unsigned message, WORD wparam, LONG lParam) 10 : FARPROC lpProcAbout; / * ” About ”関数へのポインタ * / 11 : sw i tch (mes sage) 12 : 13 : 14 : case COMMAND if て wparam = IDM_ABOUT) 15 : 16 : 17 : = MakeProcInstance (About, hlnst) : 18 : DialogBox (hlnst, "AboutBox", hWnd, lpProcAtm1t) : 19 : FreeProcInstance ; 20 : break ; 22 : 23 : return DefWindowProc (hWnd, message, wParam, lParam) : 24 : 25 : case WM_DESTROY: 26 : PostQuitMessage (FALSE) ; break ; 28 : 29 : default: return DefW i ndowProc (hWnd, message, wparam, 1 param) : 30 : 31 : 32 : return NULL; 33 : } 34 : 35 : 36 : BOOL FAR PASCAL 37 : About (HWND hDlg, unsigned message, WORD wparam, LONG lParam) 38 : { 39 : switch (message) 40 : 41 : case WM_INITDIAIÆ: 42 : return TRUE ; 43 : 44 : case WM_COMMAND: if (wParam = IDOK Ⅱ wParam = IDCANCEL) 45 : 46 : else
符号つき整数が , それと等しいかある いは大きなサイズの符号なし整数に変 換される場合で , もしその符号つき整 数の値が非負であったならば , その値 は変化しない。そうではなくて , もし 符号なし整数がより大きいサイズであ ったならば , 符号つき整数は , まずそ の符号なし整数に対応する符号つき整 数に変換され , その後にその値は , そ の符号なし整数が表現可能な最大値に 1 を加えた数を加算することで符号なし へと変換される。 ANSI C て、は「値保存 (value preserving) 」 と呼ばれるルールを普遍的に採用している。 これに対してもうひとつ別のルールがある。 それは「符号なし保存 (unsigned preservin g ) 」と呼ばれるものて、ある。 K & R 時代には 原則としてこちらのルールが採用されてい た。この場合 , 一度符号なしになった整数 データは , キャストされないかぎり符号っ きの整数データには変換されない。この意 味て、このルールの第 1 文は , ANSI になって こそ意味を持っといえる ( もっとも , 内容と しては当たり前のことて、あるが ) 。 値保存と符号なし保存のふたつのルール の差異は , 幅の狭い符号なし整数が , より 幅の広い符号つき整数へと変換される場合 に顕著となる。詳しくは後述の通常の算術 変換の項て、述べるが , とくに大小比較の演 算を伴う場合などは K & R と ANSI て、は結果 がまったく逆になる場合もあるのて、注意が 必要て、ある。 なお , 後半部分にまた「表現可能な最大値 に 1 を加えた」云々という一見難解な表現が 行われているが , これまた処理系独立にな ることを狙って数学的な表現を採用したた めて、ある。 実際には , 符号っき整数の内部表現が 2 の 補数表現を採用している処理系において , 負の符号っき整数をよりサイズの大きい符 号なし整数に変換する場合には , まずその 146 C MAGAZINE 1 2 12 Fig. 2 整数格上げと格下けの際の値変換ルール ←格下げ 格上げ→ VP VP VP * 1 * 2 * 3 処理系定義 (lmplementation define) 値保存 (VaIue preserve) ( UO の最大値十 1 ) で割った正の余り S が正の数であれば VP , そうでなければ , 表現可能であれば VP , さもなけれ D まず SI に変換し , ついで UI の ( 最大値十 1 ) を加える 値を変換後の符号なし素整数に対応する符 号つき整数に変換し , その後は何もせずに ビットパターンを保ったまま符号なし整数 へと変換する ( たんに代入するだけ ) という ことになる。このことは , 逆にいえば , も し符号っき数の内部表現が 1 の補数て、あった ならば , ビットパターンに変更が施される ということを意味している。 こて、 , 符号っき整数 ( S と表す ) と符号な し整数 ( U と表す ) がそれぞれサイズの大きい SI, UI に格上げされた場合と , サイズの小 さい S0 , U0 に格下げされた場合の値に関す る規定をまとめて図示しておこう (Fig. 2 ) 。 整数のビット幅の変更などという実に簡単 に見えるものにも , 厳密にはこのように実 にめんどうなルールが存在する。もし , 移 植性を十分に考慮するならば , これらのル ールは無視てきない存在となる。 格下げは情報が一方的に失われるから , 結果が何らかの形て、元の値とは異なったも のになるのは仕方がないとしても , 格上げ の場合にも , 符号つきから符号なしへ , あ るいはその逆など , 符号の有無が変化する 場合には , やはり処理系定義だったり , 値 が変化することがある。これはアセンプラ など低級な言語に慣れ親しんだプログラマ にとっては常識だが , 高級言語 , とくに符 号なしデータをサポートしていない高級言 語しか知らないプログラマには意外に盲点 となりやすい。とくに心しておいてほしい 点て、ある。 浮動小数と整数の間の変換 浮動小数を整数に変換する際には , 小数 部分が切り捨てられる。いい換えれば 0 の方 向に丸められる。ただし , もし小数を切り 捨てた後の値が汎整数型て表現不能てあっ た場合には , 結果は不定て、ある。とくに 整数型て、格下げが起こる場合には自動的に 上位ビットが捨てられて剰余が残るが , 浮 動小数から整数への変換て、はそのような取 り扱いはされない ほかの言語て、は浮動小数 X を丸めて整数 I にするときに , X を越えない最大の整数とす るというような仕様や , あるいはもっとも 近い整数とするというような仕様を持つも のもある。数学的にはそういった仕様のほ
「型変換」 more 第 16 回 前回 , 前々回の 2 回で C における型の適合ルールに関して考 察した。今回は , 型変換に関するルールを取り上げる。 きだあきら れまて、にも何度か触れているのて、 , 以下て、 場合にこれが適用されるのかを考える。 型変換 話を簡単にするため , char のサイズは 8 ビ は算術オペランドの場合に的を絞り , 「どの ような場合」も含めて , 型変換がどのように ットて、あり , int のサイズはそれよりも大き 型の規則に付随して , 演算に際して式の い ( たとえば 16 ビット ) と仮定する。この場 行われるかを取り上げる。 型が変換されるルールについて研究してお ロ , unsigned char が表現てきる値の範囲は 算術オペランドにおける型変換 こう。まず型変換には 2 種類あることに注意 0 ~ 255 て、あることに注意しよう。そこて、 Li st 1 を実行すると結果はどうなるて、あろう したい。ひとつは , とくにソースプログラ ム上て変換を指示しなくても暗黙の内に型 算術型の式が演算の対象となった場合に か。結論からいえば , i の値は 256 になるが , が変換されてしまう場合て、ある。以下て、は ( 暗黙の ) 型変換が行われるケースて、あり , j の値は 0 になるというのが正しい結果て、あ これを暗黙の型変換 (implicit conversion) 3.2.1 はさらに以下の 5 種類に細分化されて る。 変数 i と変数 j に対して , 一見よく似た操作 と呼ぶことにする。暗黙の型変換に対して , いる。 明示的な型変換 (explicit conversion) も存 ( 3.2.1.1 ) 整数格上げ (integralpromotion) をしているが , i への代入に際しては ch 十 1 と 在する。これはソースプログラム上て、キャ ( 3.2.1.2 ) 符号つき / 符号なしに関する変換 いう式の値が代入されているのに対して , ( 3.2.1.3 ) 浮動小数と整数に関する変換 スト演算子を用いて明示的に型変換を行う j へは , ( あらかじめ 1 だけ値を増やされた ) ch 場合てある ( キャストに関しては本連載 ' 91 年 ( 3.2.1.4 ) 異なる精度の浮動小数 の値が代入されているのが違いを生み出す 12 月号を参照のこと ) 。 ( 3.2.1.5 ) 通常の算術変換 ( usu 引 arithmeti 原因て、ある。整数格上げのルールが存在す るため , 前者て、は演算が整数 ( この場合 int) ANSI 3.2 て型変換について述べられてい C conversion) て、行われるからて、ある。 るが , そこて、は大きく 2 種類のオペランド ( 被 なかて、ももっともポビュラーな規則が整 数格上げだろう。これは一言て、表現すれば , もう少し詳しく見てみよう。まず i=ch 十 演算子 ) に対する型変換があげられている。 1 において , 右辺の ch 十 1 が評価される。 総じて C における型変換は控えめて、 , かっ保 次のようになる。 こて、 ch の型は unsigned char て、ある。このた 算術演算に当たって , int と等しいかあ 守的て、あり , またマシン語レベルて、の実装 め演算に際して整数格上げを行う。 char と るいはそれよりも狭いビット幅を持つ が容易になるように規格が決められている。 int のサイズに関する仮定から , unsignedc ( 3.2.1 ) 算術オペランド (Arithmetic ope 型の値は , もしその値を int で表現する har 型て、表現可能な値は , 常に int 型て、も表現 ことができれば int へ , さもなければ un rand) 可能て、あるから , この場合 int へと符号拡張 signed int へと拡張する。 ( 3.2.2 ) そのほかのオペランド が行われる。たまたまこのプログラムては ここて「 int と等しいかあるいはそれよりも ただし ANSI 3.2 はあくまて一般の型変換 ch の値は 255 てある。したがって , 整数格上 狭いビット幅を持つ型」とは , 具体的には ( p に関する規定て、あって , 型変換が行われる げの結果 int の 255 という値に変わる。また定 場合に「どのように変換するか」という規則 lain, signed, unsigned) char, (signed, u 数 1 は言語仕様から int てあるとされる。この てある。「どのような場合に」暗黙の型変換 nsigned)short, ビットフィールド , および 結果 , 加算の答は int の 256 となる。この値が が起きるのかは ANSI 3.2 て、は触れていな enum て、ある。この規則の細部に関する検討 。「そのほかのオペランド」に関してはこ 同じく int の i に代入されるため , i の値は 256 は後て行うことにして , まず , どのような C MAGAZINE 1992 12 142
員 N more としては一般的て、あるが , 整数の符号っき 表現としては , ほとんど使われない。 もし ANSI C が符号っき整数の内部表現と して 2 の補数表現を前提にて、きるならば , の部分の表記はもっと簡明になっただろう。 実際 K & R の時代にはそのような前提がおか れていた節がある ( K & R の時代の文法は今よ りもずっといい加減だったのて、 , 明確なと ころはわからない ) 。 ANSI て、は 1 の補数表現を採用しているマ シンが実在することを考慮し , 格下げ結果 の型が符号っきの場合には結果の値を規定 しないことにしたのて、ある。たんに余分な 上位のビットを捨て去ることにしたとして も , 2 の補数表現と 1 の補数表現て、は , 結果 が負の数て、あるならば , 値がひとつ違って くるからだ。 変化しない。 で表現可能であったならば , その値は される場合に , もしその値が新しい型 符号なし整数がほかの汎整数型に変換 うに規定されている。 半について説明しよう。そこて、は以下のよ いてはすて、に説明したのて、 , 次に項目の前 する変換規則の後半 ( 格下げ時の規則 ) につ さて , 3.2.1.2 の符号っき / 符号なしに関 値保存と符号なし保存 れていると考えてよい 表現に関しては , 実質的に純 2 進数に限定さ なお ANSI においては , 符号なし数の内部 ある。 ットパターンの解釈の差異に起因するのて、 み出されるのは , ふたつの内部表現系のビ て、あることを注意しておきたい。違いが生 る。どちらもビットパターンとしては同じ ているシステムて、はこれが一 127 と解釈され j の値は一 128 になるが , 1 の補数表現を用い て , 2 の補数表現を用いているシステムて、は 具体的には , 先の List 2 のケースにおい 符号つき数の内部表現 ( 1 ) 2 の補数表現 ある数 X の符号を変えた数を一 X とする と , X 十 ( ー X ) の結果は ( 繰り上がりを無視す れば ) すべてのビットが 0 になるような表現 系をいう。 ビット幅が n の場合には , その表現範囲 となる。具体的には 8 ビットの場合ー 128 ~ 十 127 である。重みづけをして書けば , C0 式で 表現される。 X=—?-I ・ Bn ー 1 十 2n ー 2 ・ Bn-2 十 ・十 21 ・ BI 十 20 ・ BO (CO) こで , 各 Bi は , 2 進表現での第 i 桁目の値 ( 0 または 1 ) である。最上位ビットの重みだ けが負であることに注意。 2 の補数表現の場合には加減算はとくに符 号を考慮する必要はなく , 符号なし数の加 減算と同じ操作をすればよく , 特別な処理 が不要という利点がある ( ただし , 結果のオ ーパフローに関する注意は必要 ) 。 ( 2 ) 1 の補数表現 ある数 X の符号を変えた数を一 X とする と , X 十 ( ー X ) の結果はすべてのビットが 1 に なるような表現系をいう。 ビット幅が n の場合には , その表現範囲 ー 2n ー 1 十 1 となる。具体的には , 8 ビットの場合ー 127 ~ 十 127 である。 2 の補数表現に比べて表 現範囲がひとつ狭くなるのは , 0 が正の 0 ( す べてのビットがのと負の 0 ( すべてのビット が 1 ) の 2 種類ができるからである。重みづけ をして書けば , CI 式で表現される。 X = ( ー 2n ー 1 十 1 ) ・ Bn ー 1 十 2n ー 2 ・ Bn-2 十 値 ( 0 または 1 ) である。 C0 と同様に最上位ビ ットの重みだけが負であるのと , C0 と比較 すると 1 が足されていることに注意。 1 の補数表現の場合には加減算の計算作 業は符号なし数の場合と同じでよいが , 演 算の結果負の 0 が生じたら , 正の 0 に変換す るという特別なハードウェアが必要になる ( ( 3 ) 符号十絶対値 ある数 X の符号を変えた数を一 X とする と , ー X は X の最上位ビットだけを反転させ た値になっている表現系をいう。 ビット幅が n の場合には , その表現範囲 で , 1 の補数表現と同じである。具体的には 8 ビットの場合ー 127 ~ 十 127 である。 2 の補 数表現に比べて表現範囲がひとつ狭くなる のは , 0 が正の 0 ( すべてのビットが嗔とみの 0 ( 符号ビットのみ 1 , それ以外のビットはす べて 0 ) の 2 種類ができるからである。重みづ けをして書けば , C2 式で表現される。 , , で , sign(X) は , X が 0 ならば 1 , X が 1 ならば ー 1 を返す関数であるとする。 X=sign(Bn-1) ・ ( 2n ー 2 ・ Bn-2 十 ・十 21 ・ BI 十 20 ・ BO) (C2) ・十 21 ・町十 20 ・ BO (CI) こで , 各 Bi は , 2 進表現での第 i 桁目の 符号十絶対値の演算では , 符号なし数と 符号つき数の加減算でまったく異なる操作 が必要になるため , 整数の表現にこの形式 が用いられることは希である。一方 , この 方式は乗除算が比較的楽に行えるし , また 正規化が容易というメリットがあるため , 浮動小数の仮数の表現にはこの形式を用い るのが普通である。 ANSI C ー more 145
( * 2 ) 浮動小数点表現の 実数との違いに注意された い。 C や C 十十の基本型の実 装は浮重ル」、点表現て、ある。 この固定精度の表現て、は , 浮動小点て、の指数部に相 当する要素がないため , 表 現て、きる値の範囲はかぎら れるが , 少ないメモリ領域 て、多くの有行数を表現て、 きるという特徴がある。そ 、こにあげられ れゆえに ているような特定の目的に は有、ある。 84 C MAGAZINE 1992 12 ・ Complex cos (Complex& x) ・ x のコサインを返す。 ・ Complex sin (CompIex& x) ・ x のサインを返す。 ・ Complex cosh (Complex& x) ・ x の双曲線コサインを返す。 ・ Complex sinh (Complex& x) ; x の双曲線サインを返す。 ・ Complex exp(Complex& x) ・ x の指数を返す。 ・ Complex log (Complex& x) ; x の自然対数を返す。 ・ Complex pow(Complex& x, x の p 乗を返す。 ・ Complex pow(Complex& x, x の p 乗を返す。 ・ Complex sqrt(Complex& x) ; x の平方根を返す。 ・ ostream くく x ; Complex& p) ・ long p) ; 固定精度数 は re の場合は虚部は 0 て、あるとされる。 x を (re, im ) の形式て、読み込む。ただし , (re) また ・ istream > > x ・ x を (re, im ) の形式て、出力する。 算術演算子や関係演算子としては , 標準的なもの にある。 ラスの値を返す。 F ⅸ 24 と F ⅸ 48 もこれと類似した関係 いるが , Fix16*Fix16 という乗算演算子だけは Fix32 ク Fix16 クラスの演算もほかのクラスからほば独立して 算はほかのクラスから完全に独立している。また , いし , いっしょに使用してもよい。 Fix32 クラスの演 上にあげたクラスはそれぞれ独立して使用してもよ 関するアプリケーションて、扱われることが多い ( * 2 ) 。 トしている。このような数値はデジタル信号処理に 32 , 48 ビットの領域て、値を表現し各種演算をサポー られている。これらのクラスはそれぞれ , 16 , 24 , て , F ⅸ 16 , F ⅸ 24 , F ⅸ 32 , Fix48 というクラスが与え [ ー 1 , 十 1 ) の範囲の実数を扱うためのクラスとし = ) が用意されている。これらのすべての演算につい て , 結果が士 1.0 を超えた場合のためのハンドラが用 意されている。この種の取り扱いには 2 種類の状況が 考えられる。すなわち , 加減演算の結果が範囲を超 えた場合の「オーパフロー」と , 結果が規定の規模を 超えた場合 ( 規定外の値による除算や代入 , 初期化を しようとした場合 ) に起こる , 「オーパフロー」以外の すべての「範囲工ラー」て、ある。信号処理アプリケー ションて、はこれらのふたつの場合を区別すると取り 扱いやすいことが多い。ハンドラは引数をひとっ取 る。それはエラーとなった値の仮数値へのリファレ ンスて、あり , ハンドラはその値を修正て、きる。オー パフローの場合は , その値は仮数の ( 整数による ) 算 術計算の結果て、あり , 一方 , 範囲工ラーの場合は , 完全に飽和値 ( つまり正あるいは負の最大値 ) となっ ている。ハンドラのための関数がいくつか用意され ており , これらの関数とユーザ定義の関数の中から ハンドラを指定することがて、きる。ハンドラを設定 する関数は set overflow handler と set range error handler て、ある。たとえば Fix16 のために用意されてい る関数は以下のとおり ( ほかのクラスにも同様の関数 が用意されている ) 。 ・ Fix16 overflow saturate デフォルトのオーパフローハンドラて、ある。結果 は「飽和させられる」。すなわち , 正の値ならば表 現可能な最大値 ( 2 進て、 0.111111 ・・・・・ ) がセットさ れ , 負の値ならば一 1.0 がセットされる。 ・ F ⅸ 16 ignore 何もしない。オーパフローの場合 , 整数の算術演 算と同様に , このあとに続けて加減演算を「巻きこ む (wraparound) 」ことがてき , 飽和している場 合 , その値のままにしておくことがて、きる。 ・ Fix16 overflow warning saturate 標準ェラー出力へ警告メッセージを出力し , 結果 を飽和させる。 ・ Fix16 warning デフォルトの範囲工ラーハンドラてある。標準工
場合 , もし変換後その値が表現不可能て、 あったならば , その結果は処理系定義 ( im plementation-defined) て、ある。 ( a ) のルールは非常に難解な表現だが , 処 理系の動作としては , 格下げ後の型が符号 なしの場合は , 余分な上位ビットを捨てる という作業をすればよいだけて、ある。これ を数学的に剰余などを用いて規定しようと すると (a) のような表現になってしまう。規 格書としては , 処理系独立に意味を規定し なければならないため , このような場合に はかえって苦労することになるという一例 て、ある。 具体的な値て、考えればよくわかると思う。 たとえば 16 ビットの int の 862 という値が 8 ビ ットの unsigned char へと格下げされるとす この場合にはビットパターンを考えると Fig. 1 のようになる。ここて、 , 格下げされた 後の値は 94 て、ある。これは元の値 862 を , 8 ビットて、表現可能な最大の値 255 に 1 を加え た値て、ある 256 て、割った余りになっている。 参考まて、に 256 のビットパターンも図中に示 しておくのて , なぜこうなるのかを考えて 符号つきの整数となるようなプログラムを うわけて、はないが , そのような動作は C 的と 書いてみよう (List 2 ) 。 みてほしい はいえないだろう ) 。 目下の問題て、ある ch = ch 十 1 の場合には , この場合 , i の値は 128 になる。これは AN なぜ格下げした結果の型が符号っきの場 ch は符号なし整数 (char も広い意味て、は「整 SI によって保証される。しかし , j の値がい 合には結果が処理系定義となっているのか 数」て、あることに注意 ) て、あるのて、 , ( a ) のケ くつになるかは規格上は処理系依存て、ある。 というと , これは符号っき整数の内部表現 ースが適用されることになる。すなわち 256 先の List 1 のときと同じて、 , 十十 ch という演 に対する処理系の自由を認めた結果て、ある を 256 て、割った余り , 要するに 0 が ch に格納 算は ( ch の評価回数の違いを除けば ) 次式と とされる。符号っき数の内部表現手法とし される。変数 j にはこの値 , すなわち 0 が代入 同じ意味て、ある。 ては , 次の 3 種類が考えられる。 される。厳密にいえばこの代入に際して再 ① 2 の補数表現 ch 十 1 ② 1 の補数表現 び整数格上げが行われ , unsigned char の 0 こて、 , 代入の右辺の ch は int に拡張さ ③符号 + 絶対値 という値が int に拡張されて j に格納されるの れ , ch 十 1 は int の 128 という値を生み出す。 てある。 0 はいくら拡張しても 0 のままて、あ そしてその値が ch へと代入されるとき signe 現在市販されているほとんどのコンビュ ータて、は①の「 2 の補数表現」を採用している るから , 最終的に j の値は 0 となる。 dchar に格下げされるのて、ある。この場合 さて , もし格下げ後の型が符号っきだっ といってよい。この表現がいろいろな面て、も も処理系の実際の動作としては , 格下げ結 たらどうなるか。これは (b) のケースだが , 果が符号なしの場合と同様に , たんに余分 っとも合理的て、あるからだ。しかし , ごく一 なんとその結果は処理系定義て、ある。つま 部のメーカー ( 旧 UNIVAC 系 ) のメインフレー な上位ビットを捨てるにすぎないと思われ り , 規格上は規定しないということになっ ムマシンて、は②の「 1 の補数表現」を採用して る ( オーパフローしたら実行時工ラーにする ている。先の List 1 を修正して , 格下げ後が いる。また , ③は「浮動小数の仮数の表現」 というのも , おそらく規格外れの挙動とい Fig. 1 8 ビットの unsigned cha 「への格下け例 16 ビット表現 ( int ) 1 0 進 862 0000 001 1 0101 1 1 1 0 256 0000 0001 0000 0000 862 十 ( 255 十 1 ) = 3 余り 94 unsigned cha 「に格下げ格下げ後の値 ( 1 0 進 ) 0101 1 1 1 0 94 signed char から int への promotion および int から signed char への demotion List #include く stdio. h> int main(void) signed char ch; int i ; ch = 127 ; ニ ch + 1 ; 1 十十 Ch; printf( ” j return 0 ; printf()i = Xd*n" = Xd#n ” 144 C MAGAZINE 1992 12
今すぐ切ってお店へダッシュ ! 使って納得 ! お得な PC クーポン クーポンご」用上の注意点 ・ PC クーポン加盟店でご利用いただけます。 ・クーポンコーナー展示商品でご利用いただけます。 ・クーポン券 1 枚につき、券面記載の商品を 1 点だけ購 入できます。 ・クーポン券に記載された有効期間外はお使いになれ ません。 ・クーポン券は現金とはお取り換えできません。 ・クーポン券を利用して購入された商品の返品・交換は できません。 ・破損したりコピーした券は無効となります。 ・品切れの場合は販売員にお申し出下さい。 ・商品購入時にレジにてクーポン券をご提示の場合の みご利用いただけます。 ・クーポン券裏面の必要事項 [ 住所・氏名・年齢・電話 番号 ] は、来店前に記入をすませておいて下さい。 ・クーポン券裏面の記人は全項目をもれなく行ってく ださい。記入もれがある場合は無効です。 ・店頭価格に消費税を課税した金額より、券面記載の 割引金額を差し引いた金額をお支払いください。 [ 具体的なお支払例は以下の通りです ] 店頭価格 50 , 000 円で表示された商品を、額面 5 , 000 円割引のクーポン券を使用して購入する場合 TEL 03-5488-1243 〒 108 東京都港区高輪 2-19-13 NS 高輪ビル クーポンクリアリング株式会社 PC クーポン係 問い合わせ先 となり、 ( 消費税 ) 50 , 000 円 >< 1.03 ー 5 , 000 円 = 46 , 500 円 46500 円のお支払となります。
mo 化 となる。 ch 十 1 → ( int ) 255 十 1 256 このように整数格上げが行われることに よって , 幅の狭い整数型を含む演算の結果 が直観に反しない答 ( 255 十 1 256 ) になっ ている。これが unsigned char のサイズて、演 算が行われると , 255 十 1 の答は 0 ということ になり , 直観に反する結果になる。整数格 上げの存在理由はここにあると考えられる が , 実のところ , CPU て、の演算効率を狙っ ただけだという見方もある。というのは , そもそも int というのが「そのマシンて、の自然 なワード」という定義て、あり , 必然的に機械 語レベルて、も int の幅の演算がもっとも効率 よく行えるだろうと期待て、きるからて、ある。 残念ながら筆者はどちらが真相て、あるのか 知らない 一方 , j = 十十 ch て、は事情が違う。この場 合もまず右辺の十十 ch が評価される。この prefix increment の意味は , 次の代入文と ( ch の評価が 1 度だけて、あることを除けば ) 同 じて、ある。 ch 十 1 この代入式の右辺て、ある ch 十 1 は先の i へ の代入とまったく同じて、あり , したがって , int の 256 という値を生み出すことになる。問 題はこの先て、ある。この場合 , 256 という値 は再び ch へと代入される。実はここて、もう ひとつの暗黙の型変換が起きる。すなわち 数値 256 の型てある int から , 変数 ch の型て、あ る unsigned char への格下げ (demotion) が 起こるのて、ある。この場合 , int よりも ch の ほうが幅が狭いからて、ある。これは先にあ げたルールの中の 2 番目 , ANSI 3.2.1.2 に 規定されている。 そこて、は整数の格下げに関して , 格下げ 後の整数が符号っきて、あるか , あるいは符 (b) 格下げ後が符号っきのケース 格下げされる場合 , その結果は , その小 号なしてあるかに応じて , ふたつのルール さい幅の型カ俵現可能な最大値に 1 を加え 整数が , より小さい幅の符号つき整数に が定められている。 た値て、元の値を割った余り ( ただし符号は 格下げされる場合 , あるいは符号なし整 (a) 格下げ後が符号なしのケース 正 ) となる。 数が対応する符号っき整数に変換される 整数が , より小さい幅の符号なし整数に unisigned char から int への promotion および int から unisigned char への demotion List #include く stdiO. h> int main(void) uns igned char ch : int i ; int J ; ch = 255 ; = ch + 1 ; 1 printf()i = Xd*n", i); 十十 Ch ; printf("j return 0 ; 符号拡張 一般に n ビットで表現されている符号つき に注意 ) 。 8 ビットから 16 ビットへと拡張し ても , 下位 8 ビット ( 右側 ) は元々のデータと の整数データを , m > n である m ビットの 同じである。一方 , 上位の 8 ビットは常にす データへと拡張する場合に , 新しく付け加え られる ( m ー n ) ビットの各ビットの値を , 元 べて 0 か 1 であり , それは元々のデータの最 の n ビットのデータの符号ビット ( 最上位ビ 上位ビットの値に等しい。これはまた , 元々 ット ) の値とする作業をいう。 のデータが負であるかどうかと同じである。 たとえば 8 ビットのデータを 16 ビットへと すなわち最上位ビットは符号ビットとして解 符号拡張するとする。その場合 , 代表的ない 釈できる。そしてその符号ビットの値をその まま新しく追加したビットの値として用いる くつかのデータは Fig. A のように拡張され る ( 見やすくするために , ビット表示は 4 桁 ので符号拡張と呼ばれる。 ごとにスペースを入れて区切っていること Fig. A 8 ビットのテータの 1 6 ビットへの符号拡張 ( 2 の補数表現の場合 ) 16 ビットに符号拡張した結果 8 ビット表現 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 0000 0001 00000000 01100100 01 10 0100 01 1 1 1 1 1 1 0000 0000 01 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1000 0000 1000 0000 1 1 1 1 1 1 1 1 1000 0001 1000 0001 1 1 1 1 1 1 1 1 1001 1 100 1001 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 進 0 1 100 127 ー 128 ー 12 7 ー 100 ANSI C ー more 143
特集日本版断 c 几 C/C 十十 [ 70 の全貌 す。 通常ここまて、の環境を作り出すことはと ても難しいのて , 後出のメモリマネージャ とあわせて使用する方法も紹介します。 インストレーション MS-C7 のインストールにはふたつの方法 が提供されています。ひとつは Windows か らインストールする方法 , もうひとつはコ マンドラインからインストールする方法て す。 前者の場合は , 工ンハンスドモードかス タンダードモードのいずれかて、インストー ルを行います。後者の場合は , Windows の DOS プロンプトて、はなく , 純粋なコマンド プロンプトからのインストールになります。 ディスクに余裕のない場合のインストレー ションには , 少し注意しながら行うほうが 無難てしよう。 DOS, Windows, DLL, QuickWin 対応 のプログラム作成が可能な設定て , 全メモ リモデルを Windows からインストールした Fig. 4 メモリサーバ組み込み後メモリマップ ( MS ー DOS Ve 「 . 3.3C ) 場合 , 実に 80 分もの時間を要しました。コ マンドラインからの場合て、も 30 分程度必要 Param/Dev Owner name MCB PSP Size て、す。製品版て、はもう少し速くなっている 1040 0008 40320 config. sys かもしれませんが , コマンドラインからイ 1A19 IAIA 3504 command. com 800 command. com (*ev) 1AF5 IAIA ンストールしたほうが無難だといえます。 1B28 圓 00 544096 く free> ただし , コマンドラインからインストール 7.0 withSDK 3.0 」 ( パッケージのタイトル コンバイラ関連 . 20.5M バイト すると , Windows 関連のファイルがインス プロファイラ : 0.8M バイト て、はないのて、注意してください ) としたよう トールされないうえ , プログラムマネーシ Windows 関連 : 2.8M バイト てす。まだ日本語 Windows3.1 がリリースさ ャへの登録が行われないことに注意してく れていない現在ては仕方がないことてす。 となっています。 ださい 日本語 Windows3.1 がないのに開発キットだ Fig. 2 がインストール後のディレクトリ構 インストール完了後 , Windows を起動し けがあっても役に立ちませんからね。その 成てす。 てみると ,Fig. 1 のようなグループがプログ 分 , Windows3.0 対応の SDK が付属してい ラムマネージャに登録されているはずてす。 英語版との違い ます。 さらにプロファイラを必要とする場合には , SDK が 3.0 に対応しているのて、 , 当然英語 プロファイラもインストールします。プロ 版にあったようなマルチメディア関連のド 英語版と日本語版との違いは何といって ファイラのインストールは , コマンドライ キュメントやライプラリも付属しません。 も SDK の違いてしよう。マイクロソフト社 ンからのみ可能になっています。これてメ これは日本の現状を考えれば致し方ない もその点を苦慮したらしく , 英語版ては内 モリマネージャ以外のインストールは完了 容的に「 MS ー C / C 十十 7.0 & SDK 3.1 」と とだともいえます。 なっていたのを日本語版ては「 MS ー C / C 十十 また , 削除されてはいないのてすが , 量 この段階て、のディスク占有状況は , 特集日本版 Mic 「 0S0 代 C/C 十 + Ve 「 .7.0 の全貌 45 List MS-DOS Ve 「 . 3.3C での config. sys ( メモリサーバ使用 ) 用 使 サ リ モ メ りな 00 0 / ′ 8E0 3 3 8 > .1 0 List .0. 暖 Hook Vectors 13 IB IF 2F 67 22 23 24 2E 、 0