[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
この節では、要望が多いものの、GCC としてはやらない方が良いと 我々が考えているために、実装していないものを挙げる。
この機能はほとんどの場合機能しない。機能するのは、 関数の呼出しが関数定義のあるファイルと同じファイル内にあり、 かつその呼出しが関数定義の後に現れる場合だけである。 全ての呼出しがあることを検査する、信頼できる唯一の方法は、 関数のプロトタイプを追加することである。しかし、 プロトタイプを追加するのであれば、この機能を必要とする動機は なくなる。このため、この機能は追加する価値がないのである。
シフト数は、おそらく、符号なしの場合よりも符号付きの場合が多いだろう。 それについて警告を出すとうるさいだけである。
こういう代入は非常に良くあることに違いない。 それらについて警告しても、邪魔になるだけだろう。
自動的に生成されたプログラムには到達不能コードができるというのは 良くあることである。例えば、GNU C 自身のファイルの幾つかも そうなっている。
Lisp 屋としては、値を無視することに何か危険があるという考え方には
ためらいをおぼえる。
呼出し側の全部ではない、幾つかでは意味のある値を返す関数というものが
存在するのである。
値を使わないときは常に void
にキャストするようなまねをして、
プログラムを汚くする意味はないだろう。
この仮定は、‘#pragma weak’ が使われる特定のシステムでは正しくない。
こうすると、記憶領域の配置が他のほとんどの C コンパイラと互換性が なくなる。それに、別の方法で同じ結果が得られるなら、たいして重要には 思えない。これが一番関係してくる場合というのは、構造体の中の 列挙値オブジェクトであるが、その場合はフィールドの幅を明示的に 指定できるのである。
ANSI C 規格では、単なる int
で宣言されたビットフィールドが
符号付きか符号なしかの決定を実装者に任せている。このため、実質的に
C の方言が二つできることになる。
GNU C コンパイラは両方の方言をサポートしている。符号付きの方を 指定するには ‘-signed-bitfields’ を指定し、 符号なしの方は ‘-funsigned-bitfields’ を指定すれば良い。 だが、これだけでは、どちらをデフォルトとして使うのかという問題が 残る。
現在、望ましいのは、ただのビットフィールドを符号付きにするほうである。
何故なら、それが一番単純だからである。int
は、
他のどの文脈でも ‘signed int’ と同じなので、
ビットフィールドでも同様に同じにするのが最もすっきりしている。
コンピュータ・メーカの中には、アプリケーション・バイナリ・インターフェース 規約を発行して、ただのビットフィールドは符号なしとすべしと規定している ところもある。だが、ABI の中でこの問題について何か言及するのは 誤りである。これは、ただのビットフィールドの取扱いにより、 C の二つの方言が区別されるからである。 どちらの方言もあらゆる種類の機種で意味がある。 ある特定のオブジェクトファイルが、符号付きのビットフィールドでコンパイル されたか、符号なしでコンパイルされたかは、他のオブジェクトファイルとは 何の関係もないのである。たとえ、同じデータ構造の中の同じビットフィールドを アクセスしていたとしてもである。
ある与えられたプログラムは、この二つの方言のうち、その一つか、あるいは もう一方で書かれている。そのプログラムは、適切な方言でコンパイルすれば、 ほとんどどんな機種でも動く可能性がある。一方、正しくない方言で コンパイルすれば全く動作しない可能性がある。
多くのユーザは、機種を越えて一様な環境を提供するので GNU C コンパイラを 受け入れているのである。こういうユーザは、GCCによるただの ビットフィールドの扱いが、機種によって違っていたら不便で仕方がないだろう。
時々、ユーザはある特定の機種むけにプログラムを書くことがある。 そういう場合、GNU C コンパイラが、その機種用の他のコンパイラと同じ 方言をデフォルトとしてサポートしているとユーザには便利であろう。 だが、そういうアプリケーションは滅多にない。一つの機種ではなく、 複数の機種で走るプログラムを書いているユーザは、この手の互換性から 得られるものはない。
GCC が、全ての機種型で、デフォルトでは、ただのビットフィールドを 同じ形式で扱うのは以上のような理由による。
全ての機種でデフォルトでビットフィールドを符号なしにしたらどうかという 議論が幾つかある。例えばこれが、一般に普及した実質的な標準にでも なったなら、GCC がそれに従うのは意味があることだろう。 これは将来考慮しても良い問題である。
(もちろん、ユーザは移植性のことを第一に考えて、 ビットフィールド毎にそれが符号付きか符号なしかを明示的に 指定するべきである。そうしておけば、どちらの C 方言でも同じ意味を 持つプログラムになる。)
__STDC__
を定義しないこと。
現在、GCC は、‘-traditional’ を指定しない限り __STDC__
を
定義する。これは、実践的には良い結果が得られている。
プログラマは普通 __STDC__
についての条件式を使って、
ANSI C の特定の機能、例えば関数のプロトタイプや ANSI C のトークン連結機能
を使っても大丈夫かどうかを調べることができる。
素の ‘gcc’ は、ANSI C の全機能をサポートしているので、
調べた結果は「yes」になるはずである。
中には、__STDC__
を使って、特定のライブラリ関数が利用可能か
どうか調べようという人もいるだろう。だが、これは ANSI C プログラムでは
間違った使い方である。何故なら、ANSI C 標準では、ANSI C に適合する
自由独立環境用実装では、そのライブラリ機能が無くても __STDC__
を
定義すべしと言っているからである。
‘gcc -ansi -pedantic’ は、適合する自由独立環境の一つの実装であり、
それゆえ、ANSI C ライブラリが付いてなくても、__STDC__
を
定義することが要求される。
ANSI C 規格に完全には準拠していないコンパイラで __STDC__
を定義する
のは、とにかく規格に違反しているという人がいる。
これは筋が通っていない。ANSI C 規格は、ANSI C をサポートすることを
表明しているコンパイラ、例えば ‘gcc -ansi’、に取っての規格である。
オプションなしの ‘gcc’ のようなそれ以外のコンパイラ向けのものである。
ANSI C 規格で言っていることで、‘-ansi’ オプションなしの ‘gcc’ の
設計に関係してくるのは、実用上の理由のためであり、必須なわけではない。
GCC は通常 __STDC__
を 1 に定義し、‘-ansi’ オプション
を指定した場合にはさらに __STRICT_ANSI__
を定義する。
ホストによっては、システムのインクルードファイルで別の規約を
使っているものがある。それは、__STDC__
は通常 0 であり、
ユーザが C 標準に厳密に適合することを指定した場合に 1 にする。
GCC はシステムのインクルードファイルをしょりするときはそのホストの規約
に従うが、ユーザのファイルを処理するときは通常の GNU C の規約に従う。
__STDC__
を定義しないこと。
C++ から C へのトランスレータでコンパイルするように書かれた
プログラムでは、__STDC__
の値が、トランスレータの後で使われる
C コンパイラに合ったものになる。
こういうプログラムは、__STDC__
を調べて、コンパイラが使っている
C プリプロセッサの種類を決めなければならない。
トークンの連結を ANSI C の形式で書くのか、旧来の形式で書くのかに
影響してくる。
こういうプログラムは __STDC__
が定義されていれば、GNU C++ で
適切に動作する。__STDC__
が定義されていないと正しく動かない。
さらに、多くのヘッダファイルは ANSI C の場合はプロトタイプを提供する
よう書かれているが、旧来の C では提供しないようになっている。
これらのヘッダファイルの多くは、C++ の場合は __STDC__
を定義する
よう変更しないと正しく動作しない。
__STDC__
が定義されていないと、これらは全部コンパイルに失敗する
だろうし、また、C++ かどうかを明示的にテストするように変更する必要が
あるだろう。
歴史的には、GCC は、ユーザがプログラムに 空のループを入れる最もありそうな理由は遅延を入れるためなのであり、 空のループを削除しても、実際のプログラムを速く走らせることには ならないという想定の元に、「空」のループを削除してこなかった。
だが、ここでの論拠である、空でないループを最適化しても空のループに なることはないという想定は、C については成り立つが C++ の場合は 常に成り立つとは限らないのである。
さらに、‘-funroll-loops’ を指定すると、小さな空のループは 既に削除されているので、現在の動作は最適化が足りないし、一貫性も ないので、将来変更することになるだろう。
副作用の評価順序に依存するのは決して安全ではない。 例えば、以下のような関数呼び出しは、コンパイラによって異なる動作を する可能性が大きい。
void func (int, int); int i = 2; func (i++, i++); |
この二つのインクリメントが何か特定の順番で評価されるという
保証は(C 言語規格でも C++ 言語規格でも)ない。
どちらのインクリメントが先に来ても良い。func
が
受け取る引数は‘2, 3’ かもしれない、‘3,2’ かもしれないし、
あるいは ‘2, 2’ ということさえありうる。
厳密に言えば、ANSI C 標準では、volatile のフィールドを持つ構造体を レジスタに置くことをなんら禁止していない。だが、無意味なことだと 思われるし、おそらく読者がやりたいと思っていることでは内だろう。 このため、本コンパイラはこういう場合にエラーメッセージを出すように している。
This document was generated
using texi2html 1.78.