移植 - みる会図書館


検索対象: 月刊 C MAGAZINE 1991年5月号
67件見つかりました。

1. 月刊 C MAGAZINE 1991年5月号

C プロクラム 移植入門 特☆集 C 言語と他言語を隔てる大きな要因のひとつか , その高い移植性だといわれている。 C 言語隆盛の原 動力となったといっても過言てはないだろう。ではその移植性とはなんてあろうか。 C 言語プログ ラムすべてか高い移植性を有しているのてあろうか。 C 言語すなわち移植性か高いと即断するには 危険か大きすきはしないか。 C 言語本来に備わる高い移植性とは何かを改めて考えたい。 きだあきら 一 = 己を語る ム性 = 言え ラ植ムか グ移ラか ロいグカ 五ロ フ高ロ = = ロ 高はな O る ので適るす 植現はて考 移し語れを もか一 = 三ら面 しし O げ側 す。であの はなるった = 言で保ひの o 語確のこ C 言語移植匪の実像 ム開発が行われています。 CPU のサイズて、 gramming Language 』 ) には「少し気をつけ いえば , 8 ビットのマイクロプロセッサか れば (With a little care ) C て、『移植可能』な 移司とは ら , 、 16 ビット , 32 ビット , 64 ビット , ある プログラムを書くことは容易て、ある」と記さ いはそれ以上のものにまて℃コンパイラが用 れています。しかし , 実際に種々のマシン , 意されているのて、す。筆者は寡聞にして知 一般に C 言語は移植性のよいプログラミン 種々の OS の間て、プログラムの移植作業を行 りませんが , ひょっとすると 4 ビット CPU 用 グ言語だといわれています。その噂は UNIX った経験からすれば , このさりげない「少し の普及とともに広まり , すてにその「事実」 気をつければ」というただし書きには , 想像 の C もあるのかもしれません。またコンヒ。ュ ータのグレードて、いえば , 下は器機組み込 以上に深い意味が隠されているという印象 は神話の域にまて達したといってもよいか もしれません。最初の C の教科書てある K & み用のシングルチッブマイクロコントロー を受けます。 ラから , 上は CRAY などの正真正銘のスー R(Kernighan&Ritche 著 TThe C Pro 現在 , あらゆるところて℃によるプログラ 40 C MAGAZINE 1991 5

2. 月刊 C MAGAZINE 1991年5月号

ク、一 パーコンヒ。ュータに至るまて、 , 広いスペク トルのマシンのための多数のソフトウェア プロジェクトが C て、記述されています。そし て , 開発責任者にプログラミング言語とし て C を選択した理由を問いただすと , 「移植 性がよいのて、 , 将来にわたって複数のソフ ト・ハード環境への応用が期待て、きるから」 という回答が理由のひとっとしてあげられ るのは茶飯事となっています。 しかし , 筆者はそれらの開発担当者が実 際どれほど移植性を真剣に考慮しているの だろうかと不安を感じます。 C は決して魔法 のプログラミング言語て、はありません。後 て、詳しく述べますが , C て、コーディングしさ えすれば , すべてのプログラムが自動的に 移植可能なものになるわけて、はありません。 本特集て、は , C における移植性に関して多数 の観点から考察し , どのような点が移植性 を低下させるのか , またどのようにすれば それらの問題を回避て、きるのかを考えてみ ます。 個人差はあるて、しようが , 一般にプログ ラミングというのは決して容易な作業て、は ありません。特定のマシンて、 , 特定の OS の 下て、 , 特定のコンパイラを使うと限定して も , 意図どおりに動作するプログラムを作 るのはたやすいことて、はありません。まし て , 移植性の高いプログラムを作るのは通 常たいへん困難な作業となります。それは , 数多くの環境と言語処理系の詳細な仕様に 関する広範な知識が必要とされるからて、す。 すべてにわたる知識を有することは現実的 に不可能なことて、すから , ある程度は想像 て補わねばなりません。本稿はそのような 想像力を働かせるためのヒントとなること を願って , 移植の際に落とし穴となりやす い間題点を論じ , 解決策の方向性を示そう と努めました。 それては本題に入る前に こて、いう「移 植性」という言葉をもう少し詳細に定義して おきましよう。もちろん用語集を作るのが 目的てはありませんから , あくまて、今回の テーマに適切なバックグラウンドを共有す 特集 C プロ るための定義て、あると考えてください 移植とは ある環境で動作しているソフトウェアを 別の環境でも同様に動作させること 多くの場合 , 移植には新しい環境にソー スを持ち込んて、再コンパイルするという作 業が伴います。この場合はソースレベルて、 の移植と呼びます。通常 , 単に移植という とソースレベルの移植を指します。このほ かに ( 少なくとも ) バイナリレベルの移植性 とデータの移植性が考えられます。 バイナリレベルの移植性とはコンパイル 後 , もしくはリンク後のファイルをほかの 環境に持ち込んて、動作させることて、す。 のようなことが可能なのは , おおむね同一 の CPU アーキテクチャのマシン間て、 , かっ 同一あるいは類似の OS を使用している場合 だけと思ってよいて、しよう。したがって , 以下て、はバイナリレベルの移植はテーマの 対象外にします。 またデータの移植性とは , プログラムて、 はなく , データ ( 多くの場合ファイル ) を別 な環境へ持ち込む場合を指します。とくに バイナリデータの場合には種々の問題が発 生しやすいのて、す。これに関しては後て、少 し触れます。 移植性とは 移植に要するソフトウェアの修正の多少 で評価する尺度である 移植の際には大なり小なりソースやデー タの修正が必要になるのが普通て、す。修正 が皆無て、よければ , そのプログラムは最良 の移植性をもっていることになります。本 稿て、は , そのような状態を「移植可能」と呼 ぶ場合があります。これは何もそれ以外の 場合に「移植不可能」て、あるという意味て、は なく , 修正の必要なく移植て、きるというこ とを表しています。 一般にはある規模以上のソフトウェアて は , なんらかの変更が必要て、す。全体の修 正の程度 ( 分量 ) て、移植性の良否を評価する ことになります。移植性を評価する絶対的 フム。 特集 C プログラム移植入門 41 があります。それらの言語の移植性に関す 世の中には数多くのプログラミング言語 移生が高いのか 当に ず変更しなくてはなりません。 マシン ( CPU ) 依存なのて、 , その部分はかなら しかしコンパイラは , 本質的にターゲット 以下の話が適用て、きる点は多いと思います。 ら , コンパイラ自身の移植性に関しても , を借りつつ C て、記述するのが半ば常識て、すか C コンパイラ自身も , lex や yacc などの助け の移植性のことて、はありません。もっとも ます。 C 言語の処理系 ( コンパイラ ) それ自身 フトウェアの移植性」という意味て、使ってい いますが , これは「 C によって記述されたソ なお , 「 C の移植性」という表現を頻繁に用 コーディングの方針が違ってきます。 のて、しようか。それぞれの場合て、 , 自ずと 場合にも移植性を確保しなければならない とも , 今後の C のさらなる文法変更があった パイラに対してだけなのて、しようか。それ 最後に , 移植性を確保するのは現在のコン サポートしなければならないのて、しようか。 ようか。コンパイラの文法はどの範囲まて、 OS の上に移植てきなければならないのて、し なけれならないのて、しようか。どのような はいったいどんなマシンの上に移植可能て、 済的な方針となります。そのソフトウェア うえて、必要十分な努力を行うというのが経 性を確保すべきて、あるかを見定めて , その 要します。したがって , 「どの範囲て、」移植 せん。ただしその場合 , 少なからず労力を 保て、きるならばそれにこしたことはありま プログラムを作成する場合 , 移植性を確 ります。 ど , 修正の必要な箇所は増加する傾向にあ ェアの機能を有効に利用していればいるほ に凝ったものてあればあるほど , ハー アの規模が大きくなればなるほど , 機能的 断基準に基づいています。一般にソフトェ な基準はありません。あくまて、主観的な判

3. 月刊 C MAGAZINE 1991年5月号

フム。 C プロ ク、一 特集 ソフトウェアを得ることがて、きるというわ 植性に貢献しています。関数て、提供されて はりむやみな言語機能の拡張は , 移植性に けて、す。ただ , 漫然と「動けばよい」といっ いる機能は , 移植先の環境用に外部仕様が 与える影響が大きいといえます。 た態度て、開発されたソフトウェアに高い移 一方的に C にばかり目を向けずに , 少しほ 同一の関数 , すなわち工ミュレーション関 植性は期待て、きないと悟るべきて、しよう。 数を作りさえすれば , 後のソースには手を かのプログラミング言語について補足して すなわち , このようにいうこともて、きるわ 加える必要なく移植て、きます。場合によっ おきましよう OC を用いるときほど細心の注 けて、す。 意を払うことなく , しかも C と同等以上にソ てはマクロを定義すればすむケースもあり すべての C プログラムカ夥植性カ塙いわ ます。マクロといえばプリプロセッサて、す ースレベルて、高い移植性をもったプログラ けではない。注意深く書かれた C のプロ が , これを備えていることは , 移植作業を ム記述を可能にするプログラミング言語も グラムだけが良好な移植性を有する スムースにしてくれる強力な機能のひとつ 実在しているように思えます。たとえば , て、は , C の移植性は高いといわれるように を有していることになります。 Modula-2 や Ada, あるいは Common Lisp なった理由はなんて、しようか ? 理由はい これが , 各コンパイラて、勝手に組み込み などの言語はその一例て、す。しかし , 現実 ろいろあるて、しようが , UNIX の成功が大き 機能を拡張していっているような言語て、あ に移植性の良好なソフトウェアを開発しよ なウェイトを占めているように思えます。 ればどうて、しようか。もしそれらの組み込 うとした場合に , コーディングを行う言品 UNIX というオペレーティングシステムは , み機能が , ューザレベルの関数 ( や手続き ) に何を選択するべきかという候補としては , その大部分のコードが C て、記述されていた結 によってエミュレーション不可能なものて、 それらの言語はふたつの点て、ポイントが低 あれば , 移植作業は非常に煩雑なものにな 果 , 異なる CPU アーキテクチャをもつマシ くなってしまいます。 ンへの移植が可能て、あるとされます。実際 ってしまいます。たとえば Pascal において ひとつは , それらの言語の処理系が C ほど UNIX は数多くのマシンて、動作しています。 は , 引数の数が可変て、あるような関数 / 手続 はポピュラーて、ない点て、す。これはかなり きをユーザレベルて、定義する手段が , 少な UNIX の登場以前は移植可能なオペレーティ 致命的な欠点といえます。現実に移植した ングシステムなど非現実的て、あると考えら くとも「標準」の処理系にはありません。あ い環境に ( 優秀な ) 処理系が存在しなくては れていたようて、す。このことが , 「 C て、記述 る特定の Pascal 処理系が組み込み機能とし いくら優れたプログラミング言語とはいえ て引数の個数が可変て、あるような関数 / 手続 すれば , オペレーティングシステムて、すら 採用するわけにはいきません。もうひとつ きを「ユーザの便宜のために」提供し , それ 移植可能になる」と拡大解釈されたフシがあ は , C に対する UN Ⅸのような強力かっ親密 ります。現実には UNIX の移植にはそれなり を利用したソフトウェアがあったとすると , なホスト環境がそれらの言語には存在しな その「便利な機能」がアダになり , ソースレ の苦労がつきまとうようて、す ( ただし , それ い , 少なくとも多種類のマシン上に普及し て、も移植て、きるのてすから大したことて、 ベルて、の別な PascaI 処理系移植は非常に困 た環境とては存在しない点てす。 難な作業となります。すなわち , いささか 後て、詳しく説明しますが , ソフトウェア また , 現状て、は C はもっとも広範なコンヒ。 逆説的て、すが , こういえるて、しよう。 の開発と移植を考えた場合には , それが動 C の移植性が高いのは , 裸の機能が低い ュータに用意されたコンパイラ言語だとい 作しているオペレーティングシステムが提 えるのてはないて、しようか。かって , すへ 供する環境は非常に大きな影響力をもちま からである す。 UNIX が動作している環境てあれば C に てのコンヒ。ュータに FORTRAN が用意され もちろん , 少なからぬ数のコンパイラて、 るといわれた時代がありましたが , シング 拡張言語機能が用意されているのは事実て、 とって親和性が高く , OS 機能の効率的な利 ルチップのマイクロコントローラの登場て、 用が可能て、す。さらに yacc や lex をはじめと す。たとえば i80X86 用のコンパイラ特有の拡 する各種ツール群を利用することが可能て それは怪しくなってきました。しかし , FOR 張としては near,far,huge をはじめとする TRAN はなくても C ならば用意されていると メモリモデル ( セグメント ) 関連のキーワー あるという付加的なメリットも見逃がせま ド追加があります。こういったものは特定 せん。それらのツールと C を組み合わせて , いうケースが多くなっています。処理系が 用意されているということは , 移植性を論 容易にプロトタイビングを行うことがてき のアーキテクチャ上どうしても必要て、ある じる場合の前提条件としてもっとも重要て、 ものが多く , ほかのアーキテクチャへ移植 るのは , 多少の欠点に目をつぶっても余り する場合にはプリプロセッサを利用して空 あることはいうまて、もありません。 ある利点に思えます。 て、は言語の機能レベルを考えてみましよ に置き換える ( 実質的に削除する ) ことてす ということて , 最終的な結論はこうてす。 う。 C は比較的小さい組み込み機能しかもた んて、しまう場合が少なくありません。しか 問題は少なからすあるが , 現時点で C を ず , 関数ベースて必要な機能を実現してい 用いるのは移植性に対する最良の解答 しそうて、ないケースもあり , その場合には くタイプの言語てす。このことが良好な移 移植上の問題として残ってしまいます。や のひとつである 特集 C プログラム移植入門 43

4. 月刊 C MAGAZINE 1991年5月号

る評価もさまざまて、す。移植性という観点 からみれば , つねに最低の評価を受けてい るのは機械語やアセンプリ言語などの , 別 名「低水準言語」て、す。これらは明瞭に CPU のアーキテクチャに依存しています。 一方 , 高水準言語 ( 高級言語とも呼ばれま す ) は通常移植性が高いといわれています。 それは高水準言語て、は , 機能を抽象化して プログラマから CPU のアーキテクチャをは じめとする物理的な環境を包み隠すように しているからて、す。先の移植の定義からも 明らかなように , ソフトウェアの移植性を 阻害する根本的な原因は , 環境への依存部 分が存在することにあります。裸の環境に 触れることがて、きない言語て、あれば , 当然 ながら環境への依存度が低下し , 反比例的 に移植性は良好になるわけて、す。 以上の説明から , C は本当に移植性のよい プログラミング言語なのだろうか ? う疑問をもった人もいるのて、はないて、しよ うか。「 C はアセンプリ言語のフレキシビリ ティとアセンプリ言語のパワーを合わせも った言語て、ある」というショークが示すよう に , 高水準言語のなかにあって C はアセンプ リ言語に近い面を有しています。あるいは , C は高水準言語て、はない。あれは中水準言語 て、あるという意見もあります 0K&R にも「 C は比較的低水準の言語て、ある」と記されてい ます。先の比較論て、いえば , 物理的な環境 を包み隠さずに , プログラマに比較的あり のままに裸の環境を見せているのが C なのて、 す。そのような言語て , はたして移植性の よいソフトウェアを書くことが可能なのて、 しようか。 組み込みの 8 ビットプロセッサ用のプログ ラムとスーパーコンヒ。ュータ用のプログラ ムとの間て、移植性のあるプログラムが書け るならば , これはもう願ってもないことて、 す。しかし両者の間て、 , 大規模なソフトウ ェアがほんの一部のソースの修正だけて、移 植て、きるなどとは , なんとなくありそうも ないような話にも聞こえてきます。 現に , 同じコンヒ。ュータ ( たとえはア C ー 9801 ) 42 C MAGAZINE 1991 5 の上て、 , 同一のオペレーティングシステム ( たとえば MS ー DOS ) を使っている場合て、す ら , たかが使っているコンノヾイラが違うと いうだけて、 , ソースプログラムがコンパイ ルて、きないとか , コンパイルはて、きたもの の期待したとおりに動作しないという話は 随所に転がっています。 また本誌をはじめとする雑誌類に , よく 「〇〇〇プログラムの△△△への移植」など という記事が載っているのを目にします。 もちろんそれらのプログラムは C て、書かれて います。移植先の△△△は別なコンヒ。ュー タシステムて、あったり , 別な OS て、あった り , 別なコンパイラて、あったり , ときとし て同じコンパイラの異なるバージョンて、あ ったりします。そもそも C が完璧な移植性を 備えたプログラミング言語て、あれば , この ようなテーマが記事になるはすはないて、し このような事態を目の当た ると , いずれが正しいのかわからず , よんとなく 狐につままれたような気分になる人もいる のて、はないかと思います。筆者の最初の主 張はこうて、す。 C は特別に移植性に優れたプログラミン グ言語ではない 詳細は後て、述べますが , C の言語仕様はか なりの部分が「処理系依存」て、す。裸の環境 に直接依存しているかどうかに関わらず , ソースプログラム上のまったく同一の記述 がコンパイラによって異なる解釈をされた り , ターゲットマシン上て、異なる動作をし , 異なる結果を得る場合があるのて、す。正式 に決定した ANSI C 規格て、すらそうなのて、す から , それ以前の de facto standard( 事実 上の標準 ) しか存在しなかった時代のコンパ イラ間には , 言語仕様の細部の相違がかな り存在すると考えねばなりません。 しかも , C て、はその高い自由度を反映し て , 環境に強く依存するコーディングを行 ことも容易て、す。当然ながらそれらのコ ーディングがなされてしまうと , 移植がき わめて困難なプログラムとなります。それ らの環境に依存したコーディングは , グラマがとくに意識していなくても , っとした不注意からなされてしまうことが あります。したがって , 次の主張はこうな ります。 ちょ プロ 注意深く気配りをしておけば , そのような 移植性を高めようと , あらかじめかなり こともできる C では移植性の高いソフトウェアを書く 以下のようになります。 とはて、きません。したがって , 第 3 の主張は 移植されています。この事実を否定するこ 本来意図していなかったて、あろう環境にも からぬ数のツールは MS ー DOS など開発者が て、の移植性が保たれています。さらに少な テクチャの CPU て、あっても , ソースレベル 動く環境て、あれば , まったく異なるアーキ ツールのほとんどは UNIX に類似した OS が ているのもまた偽りのない事実て、す。 GNU 群は , その大半が多くのマシンへ移植され 出されている数多くのソフトウェアツール しかし , たとえば GNU プロジェクトて、生み 移植性をもつわけて、はないと主張しました。 C て、書かれたすべてのソフトウェアが高い ことが予想されます。 ような言語は汎用言語としては使用てきな う。もちろん例外もあるて、しようが , その ことはかなり限定されたものとなるて、しよ するとすれば , おそらくその言語て、て、きる 性を保っことがて、きる「安全な」言語が存在 す。もし , どんな記述をしても完璧な移植 い実行効率の裏返してあると考えるべきて、 ログラムも書けるというのは , 自由度と高 狙っているのて、す。移植て、きそうもないプ 行効率と記述の簡潔さを両立させることを 制限しか課さないことて、 , 結果的に高い実 グラマに高い自由度を与え , 必要最小限の において , 処理系のインプリメンタとプロ するものて、はありません。 C はその基本設計 グ言語として劣っている」ということを意味 しかし , これが「 C すなわちプログラミン を書くことができる C では移植性のきわめて悪いプログラム

5. 月刊 C MAGAZINE 1991年5月号

ファイルの 書き出しタイミング 3-4 て、す。すなわち , 一定のデータがくるまて くに問題になるのが出力のバッファリング 理系 ( OS ) と行わない処理系があります。と 入出力に関してバッファリングを行う処 バッフアにためておいて , あるとき , まと めて実際の出力動作を行うような場合て、す。 たとえば画面にプロンプトメッセージを出 力した後て、キーポードからの入力を待ちた いような場合には , 入力に先だって確実に 出力を完了させておきたいわけて、す。そう て、ないと , プロンプトなして入力待ちとな り , 入力を終えてからプロンプトが表示さ 3 れるという間抜けなことになりかねません。 一般にそのような場合には , 出力先のスト リーム ( たとえば stdout) に対して fflush 関数 を呼ぶことて、バッファリングされている内 容を吐き出すようにします。バッファリン グが行われない OS の下て、開発したソフトウ ェアは , おうおうにしてこれがおろそかに されがちて、す。 MS ー DOS 処理系間移植の落とし穴 系依存が避けられない現状て , c 言語プログラ は微妙な相違が存在する。この相違が実際の AN 準拠とうたわれてはいても , 各処理系に ムの移植性確保の方策を探る。 S=DOS 用の 66 C MAGAZINE 1991 5 ど甘くありません。実際にはそれらの間の 移植可能に思えます。しかし現実はそれほ ャも OS も共通て、すから , 一見何も問題なく 場合はどうてしようか。 CPU アーキテクチ いくっかの処理系の間て、ソースを移植する それては , MS-DOS 上て、提供されている います。 じるということがおわかりいただけたと田 化が大きい場合は実にたくさんの間題が生 る可能性を秘めた言語とはいえ , 環境の変 てきました。いくら C 言語が移植性を高くす ャも OS も限定せずに一般的な移植の話をし PARTI, PART2C, CPU アーキテクチ C 几理系について 移植はかなり困難なケースが多いといわざ るをえません。 その背景には , DOS 用の C 処理系の数が非 常に豊富て、あることも遠因として存在しま す。過去から現在にかけて , DOS 用として 数多くの処理系が提供されてきました。い くつかのコンパイラベンダーは競合に負け て撤退してしまいました。まさに , MS-DOS は C の激戦区だといってもいいて、しよう。と ころて、 , MS ー DOS マシンが使用している i80 X86 という CPU のアーキテクチャは , およそ C 向きとはいえないところがあります。それ にもかかわらず , このようにたくさんの処 理系が供給されているということは , それ だけ DOS の市場が広くて魅力的だというこ となのて、しよう。 一般にコマーシャルべースて、複数の処理 系が存在した場合に , 何かしら他との差別 化を図らなければ生き残ることはて、きませ ん。必然的に , 各社は他社の処理系とは異 なる機能や性能を実現しようとしてしのぎ を削ることになります。当然ながら各社が 独自に追加した機能は移植性を低下させま す。一方 , コーディング上の問題もないわ けて、はありません。 MS ー DOS て、は比較的自 ードウェアに密接した作業をユーザ 由にハ プログラムに許してしまいます。実際には OS が提供している機能が不十分てあるた め , あるいはほんの少して、も性能を高めた いがために , 不本意にもシステムのアーキ テクチャに依存するコーディングを多用す る場合がよくあるのて、す。ところが , そう いう部分に限って処理系間て、互換性が低か ったりするのて、す。

6. 月刊 C MAGAZINE 1991年5月号

初の文法て、あるとするならば , ごく大ざっ ばにいって C はそれ以来文法の修正を 2 度受 けています (TabIe 1 参照 ) 。 C て、記述したソフトウェアの移植性を論じ る場合 , どの範囲の文法に関して移植性を 保証するのかがまず問題になります。たと えば , 明らかに関数プロトタイプを用いて コーディングされているソースの場合には , ANSI C コンパイラのレベルて、しか移植可能 にはなりませんにの点に関しては後述しま す ) 。なお , 本稿て、は K & R と V7 を総称して 「古い C 」と呼びます。 幸いにも , 新しい文法が導入されたとき には , 可能なかぎり古い文法のスーパセッ トとなるように考慮されてきました。 K&R の古い文法に沿って記述されたソースて、も , 多くの場合は ANSI C コンパイラて、そのま ま , あるいはごく些細な修正て、コンパイル て、きます。したがって , 次のことがいえま す。 最大限の移植性を確保したければ , 古 い文法の範囲内でソースを記述せよ ただし現実問題として , 今や純粋の K & R 文法のコンパイラはほとんど残っておらず , 大部分のコンパイラは V7 文法か ANSI C だ と思ってもよいて、しよう。そこて、 , 筆者は 非 ANSI コンパラへの移植性も確保せざるを えない場合には , V7 の文法の範囲て、記述す ーー・移植上の障害点 K&R と ANSI C の相違 ることて妥協しています。 れば , ほとんどの場合 V7 に対しても移植は ら , K&R と ANSI C に対して移植可能て、あ 外を除けば両者の中間に位置していますか ておきましよう。 V7 コンパイラは少数の例 能なソースを書くための基本方針を解説し その前に , K&R と ANSI C の間て、移植可 にウェイトをおいて解説します。 違に関して , 移植上の障害になるような点 K&R と ANSI C, および V7 の文法間の相 基本的な方針は , なるべく K & R の文法の 枠内て、記述するというものて、す。しかし , どうしても両者て、矛盾してしまう部分もあ ります。そのような場合の対策は条件コン パイルて、す。すなわち , プリプロセッサを 利用して , ある種のプリプロセッサシンポ ルが定義されているかどうかて、コンパイル すべきソースの一部を変化させようという ものて、す。多くの場合 , マクロの定義を変 更したり , 付加的なヘッダを # include したり して対処します。 ANSI C 準拠のコンパイラの場合 , STDC というプリプロセッサシンポルは 1 と #define されることになっています。した がって , 次のような条件コンパイルを行え ばよいように思えます。非 ANSI コンパイラ の場合 , そもそも STDC は定義されて いないはずだからて、す。ここて、 , # if defined ( STDC ) と記述するのは避けるべきて、 す。なぜならば , defined( 識別子 ) というの は ANSI C て、導入された機能だからて、す。 #ifdef STDC / * ANSI コンノヾイラの場合 * / #endif たいていの場合これて、うまくいきますが , ほとんど ANSI C の規格に準拠していなが ら , いくつかの理由から STDC が 1 にな っていない処理系も存在します。そのよう な処理系を用いる場合には , コンパイル時 たとえばコンパイラに対するコマンド ラインオプションて、 STDC を定義する か , あるいは STDC に頼るのをやめ て , 自前のプリプロセッサシンポルを用い ます。本稿の後半を読んて、いただくとおわ かりになると思いますが , ANSI C かどうか 以外にも , 環境に特有のパラメータをいく つか指定しなければならないケースがほと んどて、す。そのような場合にも , 自前のプ リプロセッサシンポルを用いて条件コンパ #else / * 非 ANSI コンパイラの場合 * / イルをすることて、 ( たとえばマクロの定義 内容を変えて ) 対処します。 自前のプリプロセッサシンポルを用いな ければならない場合は , たとえば環境に依 存する部分を制御するためのヘッダをひと つ用意して , environ. h とて、も名前をつけ , その中に環境依存の部分をすべて閉じ込め るようにします。そうすれば , 移植する場 合にはこのヘッダだけを修正すればよいは ずて、す OANSI C かどうかによって動作を変 化させたい場合は , このヘッダ中て、次のよ うに記述すればよいて、しよう。 #define ANSI / * undef if not ANSI * / #ifdef ANSI / * ANSI コンノヾイラの場合 * / #else / * 非 ANSI コンパイラの場合 * / #endif このようにして , もし ANSI C を用いる場 合には #define ANSI をいかしておき , 非 ANSI コンパイラの場合にはコメントにして 殺してしまうという手段が考えられます。 あるいは , ソースの中に #define ANSI を入 れるのはやめて , コンパイル時のオプショ ンて、定義してもよいて、しよう。 それぞれの条件コンパイルの場合に , 具 体的にどのような作業を行うべきかは以下 て、述べます。 バラメータタイプリストと 関数プロトタイプ ANSI C が導入した新しい機能のうち , コ ーディングスタイル上もコンパイラ処理上 もいちばん重要て、あり影響力があるのは , パラメータタイプリストと関数プロトタイ プて、あることは論を待ちません。 ラメータタイプリストとは , 次の関数 f00 の 引数定義に用いられる ( long a, long b ) のカ 可能となります。 46 C MAGAZINE 1991 5

7. 月刊 C MAGAZINE 1991年5月号

C プロ ク、一 フム。 なる配列を確保て、きるということに仕様を ンタの大小比較は違う作業が行われます。 にすることが可能てす。 限定していることてす。ここ <size の型は size この結果 , 勝手なセグメント値とオフセッ この考察に基づいて , ポインタの生成 ( & ト値からポインタを作り出して大小比較を の適用や式の中に出現した配列オプジェク t てあり , これは unsigned int< あることに 行わざるをえないような場合には , ポイン トからのポインタへの変換 , メモリ割り付 注意しましよう。 タが far て、あるか huge て、あるかて、 , まったく け関数が返す値など ) や , ポインタ値への加 MS-C5, MS ー C6 のマニュアルには , この 異なった結果を得ることがあります。 huge 減算のときだけ正規形への変換作業 ( 正規 size 引数には「配列全体の大きさ ( 筆者注 : n モデルて、コンパイルすることを念頭に開発 化 ) を行うことて、 , 大小比較に際しては un * size バイト ) が 128K バイトを越える場合 signed long と同等の作業て、すませてしまう には , 引数 size は , 2 のべき乗て、なければな されたソースを TCC へ移植する場合にはこ という方針て、す。今回調べた処理系て、は , りません」という奇妙な ( と思える ) 制約が記 のことを十分注意しなければなりません。 LAT と TCC 以外のすべてがこの方針を採用 本稿の最終的な結論はこうて、す。 載されています。この制約は MS ー C5 , MS- 移植て、きそうもないコードを書くときに していました ( なお , LSI には huge モデルも C6 が採用しているポインタの正規形と無関 移植を楽にするためにとるべき基本的な方 huge ポインタもありません ) 。また , TCC は 係て、はありません。詳しいことは省略しま 実は正規化も行っています。しかし正規化 すが , halloc て、構造体を要素とするような配 針は , ・環境に依存する部分をほかの部分から の方針が MS ー C5 , MS-C6 と TCC とて、は違い 列を割り付けた場合に , ちょうど正規化さ 切り放し局所化せよ れたポインタのセグメント値が切り換わる ます (Fig. 6 参照 ) 。 ・できればそれをマクロや関数を用いて いずれも , 32 ビットの整数値として比較 境界上にまたがって位置してしまう要素が 抽象化せよ 出現すると , MS ー C の正規化手法て、アクセス て、きるように考察されていますが , 効率か ・そしてバラメータを設けて汎用化して するにはまずい事態が発生してしまうのて、 らいえば MS-C5, MS ー C6 の手法のほうがオ おけ ーバヘッドは少ないといえます。しかし , す。そのため , そのような要素が存在しな 任意のセグメント値とオフセット値からポ という精神にまとめられます ことを保証するための制限カ阯記の 128K い インタを構築するようなことをしてしまう バイトを越える場合には云々というものな 。 = 。移植性向上のために と , MS-C5, MS ー C6 の場合破綻しやすいと のて、す。 この違いは , TCC て、記述されたプログラ この微妙な いう欠点があります。さらに 違いが両処理系て、の 64K バイト以上の動的な ムを MS ー C へ移植する場合にかなり重大な問 以上こまごまと注意点を述べてきました。 メモリを far ヒープから割り当てるためのラ 題となります。メモリを確保するだけて、あ C は移植性がよいといわれているが , 本当だ イプラリ関数の仕様に影響を与えています。 ろうかという疑間が生じたことだと思いま れば , MS-C 側て、 dos allocmem 関数を使う MS-C5, MS ー C6 ては halloc て、す。 す。冒頭て、も述べましたが , C はその性格 ことて、対処することがてきます。しかし , 上 , ネイテイブハードウェアの特性をプロ それをアクセスする場合には細心の注意が void huge *halloc(long n, size t グラマに隠さずに見せるような言語仕様に 必要になります。したがって , 将来的に MS size),• ー C へ移植することを考えているようなソフ なっているのてす。て、すから , これくらい n 要素の個数 トウェアて、は , あらかじめメモリ割り付け 1 要素のバイトサイズ の障害は当然予測されることて、す。要は移 SlZe に際しては MS-C の halloc が要求している制 植可能という範囲の特定につきます。移植 TCC< は , この目的の関数がいくつか用 意されていますが , 代表として farmalloc を 約を満たすような形て、設計しておいたほう 性を高めようとする場合にも , むやみに移 が無難て、す。 植範囲を広げることなく , どの範囲て、移植 あげましよう。 あともうひとっ TCC て、意外に盲点になり を行うのかを十分に吟味してソースの記述 VOid far *farmalloc(unsigned やすいのは , たとえメモリモデルを huge と に注意すれば , 現実問題として移植可能な long nbyte); nbyte 確保したいメモリ領域の 指定してコンパイルしても , ポインタのデ ソフトウェアを作成することはそれほど困 バイトサイズ フォルト ( とくに near, far, huge の指定が 難て、はありません。そして , ある表現をす るときに「この表現は , 異なる環境て、も動作 重要な違いは , farmalloc が unsigned ないポインタ ) は far て、あるということて、す。 1 。 ng 型の値て指定する任意のサイズ ( 実際的 するのかどうか」を少し考えてプログラムす MS-C5, MS-C6 や LAT て、は , メモリモデル な上限があるのは当然てすが ) の連続領域を が huge て、あれば , ポインタのデフォルトも るだけて、も , 全体としての移植性はずいぶ 自動的に huge にしてくれます。先に述べた 確保てきるとしているのに対して , halloc んと向上します。そのためのヒントとして 本稿が少して、も参考になれば幸いて、す。 ように ,far ポインタの大小比較と huge ポイ は , 各要素が size バイトて、 , それが n 個から 72 C MAGAZINE 1 1 5

8. 月刊 C MAGAZINE 1991年5月号

1991 年 5 月 1 日発行 ( 毎月 1 回 1 日発行 ) 第 3 巻第 5 号通巻 20 号 1990 年 2 月 2 日第 3 種郵便物認可 980yen 短期連載・思考の周辺・統一的オプジェクト表記法 〈第 1 回〉 O 言語と O 十十 新連載・ 実力養成講座〕スタートアップ O 十十 巻頭インタビュー RObe ュ W. Scheifler(II) MIT x Window consorüum 9 「 ecto 「 明解 <ZØ-- O 一言語入門講座〈第 2 回》 O でプログラミングしよう ! 新ー OOcn プログラミング入門 / O 言語雑学講座 / 最新開発環境レポート 提携記事・ Re 一ぎぎ g Candidate Ob 一 ec お・ Ob 一 e ュ・ 0 計 ed Structured Des コ and C 十十 特別付録〕一スク ・ r<zcn— O 言語入門講座」活用ファイル②・本誌奮闘記」紹介プログラム ( X68000 版 OOO ① ) ・高級料亭「蟹味噌」 ( PC ー 9800 ) ・ューー百リー等「ー」・本誌掲載ソースプログラム 集 特 C プロクラム移植入門 I ・ C 言語移植性の実像 / Ⅱ・移植性阻害の要因と対策 Ⅲ・ MS - DOS 処理系間移植の落とし穴

9. 月刊 C MAGAZINE 1991年5月号

います。しかし , ごく一部には 1 の補数と呼 ばれる表現方法を採用しているマシンがあ ります。ビット幅が同じて、ある場合には , 両者は正の数値に関してはまったく同一て、 す。しかし , 負の数値に関してはビットパ ターンが異なります。たとえば int が 16 ビッ トてあるとすると , 2 の補数表現ては一 1 は 2 進て、表記すると 1111111111111111 て、あるの に対して , 1 の補数表現ては 1111111 111111110 てあるという違いがあります。 1 の補数表現て、は 0 の表現に関して , すべての ビットが 0 の 0000000000000000 と , 反対にす べてのビットが 1 の 1111111111111111 のふた つがあるのが特徴てす。後者を一 0 と呼ぶ場 合もあります。 1 の補数表現て、は , 2 の補数表現系になれ てしまったプログラマの意表をつくような 問題が出てきます。 f00 ( ) fO 「 (i 0xffff ; こて , int は 16 ビットだとしましよう。 数表現て、は 0xffff は一 0 てあり , すなわち 0 な い間ループが継続されます。ところが 1 の補 for のループ継続条件は i て、すから , i が 0 て、な 少し移植性にうるさい人は次のように書 i & = (0xffff < < n); 書くものてす。 16 ビットて、あることを仮定して次のように ましくないコーディングは , int がたとえば をマスクして 0 にしたい場合によくする , 好 す。たとえば , int の変数 i の下位の n ビット ほかにもいろいろ不都合なことが起きま 本体を実行しないて通り抜けてしまいます。 のて , この for ループは予想に反して一度も 64 C MAGAZINE 1991 5 しかし 1 の補数表現のマシンの場合 , これ くてしよう。 て、は ( n 十 1 ) ビットをマスクしてしまいます。 そこて、 , 正解は次のように書くことて、す。 教訓としてはこうなります。 負数を 1 の補数表現で行うマシンを考慮 して , 算術演算 ( + , 果の ( 負数の ) ビットバターンを仮定し てはならない。しかしビット単位の演 算子であれば , 負数の表現のビットバ ターンを想定してよい。 浮動小数の問題 float や double にまつわる移植上の問題も 深刻なものがありますが , 残念ながら誌面 の都合て、割愛させていただきます。 OS 環境との関係 C て、書かれたプログラムが必ずしもすべて OS の下て、動作しているとはかぎりません が , 移植性を考慮する場合に OS が重要なポ イントて、あるのはいうまて、もありません。 OS に依存しすぎているプログラムを異なる OS へと移植するのは , ときとしてハードウ ェアに依存しているプログラムを移植する よりも手間がかかります ( あるいは移植する ことを諦めてしまいます ) 。 とくに OS への依存度が高いプログラムが 横行しているのは UNIX の世界て、す。ひとっ には , プログラマにとって , 何が OS て、何が 言語のライプラリなのかの区別が , UNIX の 世界にいるかぎり , とくに意識する必要が ないということがあげられます。たとえば , fread/fwrite はライプラリて、すが , read/ write は UNIX て、はシステムコールて、す ( read / write は ANSI のライプラリには含まれてい ことに注意しましよう ) 。しかし , どこ にその違いがあるのかもうひとっ明確て、は ありません。 man(UNIX のオンラインマニ ュアル ) を見ればわかるという反論もあるか もしれませんが , 仕様を考えるかぎり区別 は明白とはいいがたいと思います。 read/ write の類はほかの OS て、も比較的容易にエミ ュレーション可能てすが , 低レベルメモリ 管理やプロセス管理 , 環境変数のアクセス など , システムコールの中にはまったく構 成の違う OS の下てはエミュレート困難なも のがあることは考慮しておくべきて、す。あ る種の signal などもこれに含まれます。特定 の OS て、しか発生しない signal があるからて、 す。 ファイルシステム関係て、いちばん問題な のは , おそらくファイル指定の規則て、しょ う。ファイル指定にデバイス ( ドライプ ) 名 やパス名がっくのかどうか , OS によっては さらにネットワークノード名がっく場合も あります。 VAX/VMS などて、はさらにファ イルタイプの後にバージョン番号がっきま す。与えられたファイル指定からパス名を 取り出したりする場合には , どのような文 字て、パス名と純粋なファイル名が区切られ ているのかを知っていなければいけません。 OS によって , その文字はソ〃 , 、、 \ 〃 , 、、く〃 , 、、 [ 〃などさまざまて、す。さらに , ファ イル名に漢字コードを含めることが可能な 場合にはさらに事態は複雑になります。 れらの処理は環境依存て、 , どのような環境 に対しても移植可能に記述するというのは 絶望的だと思います。結局 OS ごとにそれら の関数を変更する必要があります。 バイナリファイルと テキストファイル MS-DOS と UN Ⅸの間て、の移植て、よく問 題になるのはバイナリファイルとテキスト ファイルの区別て、す。 UN Ⅸには両者の区別 がありません。一方 MS ー DOS て、は区別せざ るをえません。というのも , テキストの行 末は , UNIX て、は LF だけなのに , MS-DOS ファイル指定

10. 月刊 C MAGAZINE 1991年5月号

ク、一 立場からみれば , すて、にハードウェアの一 部といえます。したがって , に依存したソフトウェアは , それらの機能 やはり機種依 TabIe 1 C 言語における文法の修正の流れ うとか , かならずマウスがあると仮定して コヒ。ーディスプレイて、あると限定してしま たとえば , 出力を 80 文字 x 25 行のソフト 入出力テパイスに対する仮定 るべきて、す。 場合には , 可能なかぎり signal の使用を考え すが , 移植性の高いコーディングをめざす ることはいうまて、もありません。後述しま システムソフトウェアに依存した行為て、あ また極度にハードウェアアーキテクチャと ンタラブトべクタの書き換えて、す。これも ングの常套手段として行われているのがイ さらに , 特定の機種におけるプログラミ インラブトべクタの参照 / 更新 ウェア依存の値て、あるからて、す。 戻されるキースキャンコードもまたハ び出し手順が機種依存て、あるのみならず , るということ自体と , その具体的な BIOS 呼 ることなります。その BIOS コールが存在す どを使用した場合には , 二重に機種依存す スキャンコードを得るために BIOS コールな 存となるて、しよう。たとえばキーポードの 特集 しまうことなどがこれにあたります。ある signed cha 「 , long double, wchar—t ほか const, volatile VOid * パラメータタイプリスト / 関数プロトタイプ 関数からの戻り値に構造体を許す , ほか 構造体の代入 , 構造体引数の値渡し 構造体ことに異なるメンノヾ名空間をもつ unsigned の形容詞化 void, enum の追加 最初の文法定義 おもな変更点 おくべきだといえます。無用な機種依存性 ないという場合のための伝家の宝刀にして コーディングは , それ以外には何も手段が それて、もシステムアーキテクチャ依存の とは事実上不可能て、す。 ば , デバイス ( ディスプレイ ) 独立に書くこ の termcap ライプラリなどの存在を別にすれ かの画面制御を行わざるをえません。 UNIX イエデイタ ) を作る場合にはどうしても何ら たとえば , スクリーンエデイタ ( ディスプレ のような場合おのすと答えは明らかて、す。 ない機能が要求されることもあります。そ 移植性を犠牲にしても実現しなければなら いるわけてはありません。場合によっては , キテクチャに依存してはならないといって しません。ただし , 必ずしもシステムアー こて、はこれ以上深入り 不可避て、すから , します。この場合の移植性の低下は明白て、 チャに依存した場合 , 移植性は著しく低下 以上のように , 裸のシステムアーキテク けません。 定のエスケープシーケンスを仮定してはい は機種依存て、あり OS 依存て、もあります。特 と , 画面がクリアされるというようなこと ) ープシーケンス ( たとえば、、 \ 033 [ 2J 〃を送る いは , スクリーンコントロール用のエスケ C プロ 移植入門 フム。 年 ' 78 '90 版名 K&R V7(UNIXVe 「 sion 7 ) ANSI は可能なかぎり避けたほうが賢明て、す。ま た , システムアーキテクチャに依存したコ ーディングをせざるをえない場合て、も , 少 しくふうをすることて、すいぶんと移植性が 高くなります。具体的なコーディング手法 に関しては後述します。 こて、いえること は次のような教訓て、しよう。 不必要なシステムアーキテクチャへの 依存は避けること どうしても必要であればコーディング 手法をくふうすること ウェア環境 の題 0 言語仕様に依存する部分 ソフトウェア環境は , 突き詰めればすべ て「言語仕様」に帰着させられるかもしれま せん。しかし , それらの詳細はほかの項目 にまわして , この項目て、は単に「そのコンパ イラが実現している文法はどの基準に沿っ たものか」という意味て、とらえます。 C 言語は , ほかの多くのプログラミング言 語と同様に , 何度も文法が修正 , 拡張され てきました。しかし誤解を防ぐためにひと こと付け加えると , C のように広い範囲て、利 用されている言語としては , むしろその文 法の変遷の履歴はささやかなものてあると いえます。ほかの言語には , それほど広く 使われているわけて、もないのに , 次々に文 法が修正 , 拡張されているものもあります。 K & R 第 1 版が登場した時点て、 , C はすてに ある程度枯れた文法を備えていました。実 際には K & R 以前の時代があり , 何度も文法 が修正されていたためて、す。それは K & R 第 1 版に「 C は進歩しつつある言語だから ( 中略 ) 初期のバージョンて、は ( 中略 ) 初期化の構文 も変更された」などという記述があることか らもうかがえます ( 付録 A : 17 時代遅れの 面 ) 。しかし , そのような事情を無視して , K & R 第 1 版によって公開された文法カ℃の最 特集 C プログラム移植入門 45