[Contents]   [Back]   [Prev]   [Up]   [Next]   [Forward]  


GNU CC の既知の不具合原因

このセクションでは、 GNU CC のユーザに影響を及ぼす既知の問題について説明します。 これらの問題のほとんどは、 それ自体は GNU CC のバグではありません。 もしバグであれば、 私たちはそれを修正したでしょう。 ただし、 これらの問題がユーザに対して及ぼす結果は、 バグがもたらす結果と同じようなものかもしれません。

これらの問題のいくつかは、 他のソフトウェアのバグによるものです。 また、 それを追加するにはあまりにも労力のかかるような機能の欠如が問題であることもあります。 さらに、 何が最善であるかについて人々の意見が一致しない領域が問題となることもあります。

未修正の本物のバグ

インストールの問題

以下は、 GNU CC をインストールする際に出てくる問題 (および、 実際には何か問題があることを意味しているわけではない、 見せかけだけの問題) の一覧です。

クロス・コンパイラの問題

いくつかの理由により、 特定のマシン上においてクロス・コンパイル処理を行う際に問題に直面することがあるかもしれません。

相互作用

このセクションでは、 GNU C や GNU C++ を他のコンパイラと一緒に使う場合や、 特定のシステム上のアセンブラ、 リンカ、 ライブラリ、 デバッガと一緒に使う場合に直面する様々な問題を一覧にして示します。

特定のプログラムのコンパイルにおける問題

プログラムによっては、 コンパイルに問題のあることがあります。

GNU CC の非互換性

GNU C と既存の (ANSI に対応していない) ほとんどの C との間には、 注目すべき非互換性がいくつかあります。 `-traditional' オプションを使うと、 他の C コンパイラと似た振る舞いをするよう GNU CC に通知がなされ、 これらの非互換性の多くが取り除かれます。 しかし、 すべての非互換性が取り除かれるわけではありません

修正されたヘッダ・ファイル

GNU CC は、 いくつかのシステム・ヘッダ・ファイルを訂正したものをインストールしておくことを必要とします。 これは、 ほとんどのターゲット・システムのヘッダ・ファイルには、 未修正のままでは GNU CC と組み合わせて使うことができないものがあるからです。 バグを持つものもありますし、 ANSI C と非互換のものもあります。 また、 他のコンパイラの特殊な特徴に依存しているものもあります。

GNU CC をインストールすると、 fixincludes と呼ばれるプログラム (あるいは、 あるターゲット・マシンでは、 例えば fixinc.svr4 のような代わりのプログラム) を実行することにより、 修正されたヘッダ・ファイルが自動的に作成され、 インストールされます。 通常ユーザは、 このことに注意を払う必要はありません。 しかし、 このプログラムが自動的には正しいことをしてくれないケースもあります。

標準ライブラリ

GNU CC は、 ISO/ANSI C 標準が conforming freestanding implementation (適合する自立した実装) と呼ぶところのものに、 単独でなることを試みています。 このことは、 すべての ANSI C 言語の特徴だけでなく、 `float.h'`limits.h'`stdarg.h'`stddef.h' の内容すべてが利用可能であることを意味しています。 これ以外の C ライブラリは、 オペレーティング・システムのベンダによって提供されます。 その C ライブラリが C 標準に適合しないのであれば、 ユーザ・プログラムは予期しない警告を (特に `-Wall' を使っている場合に) 受けるかもしれません。

例えば、 C の標準では sprintf 関数は int を戻り値とすることになっていますが、 SunOS 4.1.3 上の sprintf 関数は char * を戻り値とします。 fixincludes プログラムが、 この関数のプロトタイプを標準に合うように変更することは可能かもしれませんが、 この場合でもその関数自体は依然として char * を戻すのですから、 これで正しくなるわけではありません。

標準に準拠したライブラリが必要であれば、 それを自分で探す必要があります。 GNU CC は標準に準拠したライブラリを提供していません。 (glibc と呼ばれる)GNU C ライブラリは、 いくつかのオペレーティング・システムに移植されており、 ANSI/ISO、 POSIX、 BSD、 SystemV との互換性を提供しています。 あるいは、 より新しいライブラリが利用可能になっているかどうかを、 オペレーティング・システムのベンダに問い合わせてみることもできるでしょう。

失望と誤解

以下の問題が存在することは残念ではありますが、 実際にこれを回避するための方法を私たちは1つも知りません。

GNU C++ に対する一般的な誤解

C++ は複雑な言語であり、 しかも、 進化しつつある言語です。 その標準定義 (ANSI C++ ドラフト標準) もまた進化しつつあります。 その結果、 C++ コンパイラが時々ユーザを驚かすことがあります。 C++ コンパイラの振る舞いが正しいような場合にすらそのようなことが起こります。 このセクションでは、 この種の質問が頻繁に持ち上がるようなところについて議論します。

静的メンバの宣言定義

あるクラスが静的なデータ・メンバを持つ場合には、 その静的メンバを宣言するだけでは十分ではなく、 その定義もしなければなりません。 例えば、

class Foo
{
  ...
  void method();
  static int bar;
};

この宣言は単に、 クラス FooFoo::bar という名前の int 型のメンバと Foo::method という名前のメンバ関数を持つ、 ということを確かなものにするだけです。 まだ methodbar の両方をどこかほかのところで定義する必要があります。 ANSI のドラフト標準によれば、 1つの(ただ1つの)ソース・ファイルの中で初期化子を提供しなければなりません。 例えば、 以下のようになります。

int Foo::bar = 0;

他の C++ コンパイラは、 標準のこの振る舞いを正しく実装していないかもしれません。 その結果、 このようなコンパイラから g++ に切り替えた人は、 以前は正しく動作していたように見えたプログラムが、 実際には標準に従っていないということに気がつくことになるかもしれません。 g++ は、 定義されていない静的データ・メンバを見つけると、 それを未定義シンボルとして報告してきます。

予想よりも早く消滅する可能性のあるテンポラリ・オブジェクト

テンポラリ・オブジェクトの一部分に対するポインタや参照を使うことは危険です。 予想よりも早く、 コンパイラがそのオブジェクトを削除してしまい、 ポインタがゴミ(ガーベッジ)を指すことが当然ありえます。 この問題がもっともよく発生するのは、 libg++ の String クラスのように、 char * 型や const char * 型への変換関数が定義されているクラスにおいてです。 何らかの内部構造に対するポインタを返すクラスはいずれも、 潜在的にこのような問題を持つ可能性があります。

例えば、 あるプログラムが、 String オブジェクトを返す関数 strfuncchar 型へのポインタを操作する別の関数 charfunc を使うものとしましょう。

String strfunc ();
void charfunc (const char *);

このような状況において、 クラス Stringchar 型に対するポインタへの明示的な変換関数を持つことが分かっていますから、 それにもとづいて `charfunc (strfunc ());' と書くのは自然なことに思えるかもしれません。 しかし、 実際の動作は `charfunc (strfunc ().convert ());' に類似したものとなります。 ここで convert メソッドは、 通常キャストによって行われるデータ変換と同じことを行う関数です。 String テンポラリ・オブジェクトが最後に使われるのは変換関数の呼び出しにおいてですから、 charfunc が実際に呼び出される前に、 コンパイラはこのオブジェクトを削除してしまうかもしれません。 コンパイラには、 String を削除してしまうとポインタが無効になってしまうことを知る術がありません。 こうしてポインタはゴミ(ガーベッジ)を指すことになり、 charfunc は、 呼び出された時に不当な引数を受け取ることになります。

ほかのコンパイラでは、 このようなコードもうまく動くことがあるかもしれません。 特に、 テンポラリ・オブジェクトを削除するタイミングが比較的遅いコンパイラであればそうでしょう。 しかし、 GNU C++ の振る舞いも標準に適合しているのです。 テンポラリ・オブジェクトが遅いタイミングで削除されるということに依存するプログラムがあれば、 そのプログラムには移植性がありません。

もしこれが驚くべきことであると思われるのであれば、 ANSI C++ 委員会ではテンポラリ・オブジェクトのライフタイムの問題に関して今でも議論を続けているということを知っておくべきでしょう。

すくなくとも現在のところは、 このようなコードを安全に書く方法は、 テンポラリ・オブジェクトに名前をつけることです。 こうすれば、 テンポラリ・オブジェクトはその名前のスコープの終端に達するまで存在し続けます。 例えば、 以下のようにします。

String& tmp = strfunc ();
charfunc (tmp);

protoize の使用に関する警告

変換プログラム protoizeunprotoize は時々ソース・ファイルに対して、 再修正をしないと正しく機能しなくなるような変更を加えてしまうことがあります。

変更したくない点

このセクションでは、 人々から頻繁に変更するよう要求されるにもかかわらず、 変更していない点を一覧にして示します。 これらの変更要求を採用しないのは、 そのような変更を加えない GNU CC の方が良いと考えられるからです。

警告メッセージとエラー・メッセージ

GNU コンパイラは、 2つの種類の診断を出力することができます。 エラーと警告です。 それぞれ異なる目的があります。

警告は、 プログラムが本当に意図されたとおりのことを行っているかどうかチェックして確認するべき危険な箇所を示しているかもしれません。 あるいは、 古くなってしまった機能を使っている箇所や、 GNU C や GNU C++ の標準的ではない機能を使っている箇所を示しているかもしれません。 多くの警告は、 ユーザが `-W' オプションのどれかを使ってその警告を明示的に要求した場合にのみ発行されます (例えば、 `-Wall' は様々な有用な警告を要求するオプションです)。

GNU CC は常に、 可能であればプログラムをコンパイルしようと試みます。 プログラムの意味するところが明確であれば、 (例えば) 単に標準に正しく準拠していないという理由だけで、 いわれもなくプログラムを拒否するようなことはしません。 しかし、 C や C++ の標準によってある特定の拡張が明示的に禁止されている場合があり、 そのような場合には、 標準に準拠するコンパイラは診断メッセージを出力しなければなりません`-pedantic' オプションは、 このような場合に警告を出力するよう GNU CC に通知するものです。 一方、 `-pedantic-errors' はこのような場合に警告ではなくエラーを出力するよう指示します。 このことは、 ANSI に準拠していないすべての構文に対して警告やエラーが出力されることを意味しているわけではありません。

これらの点に関する詳細、 および、 関連するコマンドライン・オプションの詳細については、 See section 警告を要求もしくは抑制するオプション


[Contents]   [Back]   [Prev]   [Up]   [Next]   [Forward]