[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
GNU C と既存の(非 ANSIの)版の C には注意しなければならない 非互換性がたくさんある。 ‘-traditional’ オプションを指定すると、GNU C が他の C コンパイラと 同じように動作するので、これらの非互換性の多くは消えるが、 全部がなくなるわけではない。
これから生じる結果の一つに、mktemp
を文字列定数を引数として
呼び出すことができないというのがある。
関数 mktemp
は常に、その引数が指す文字列を変更する。
また別の結果の一つに、システムによっては、sscanf
に
フォーマット制御文字列あるいは入力として文字列定数を渡すと正しく
動作しないものがある。
これは、sscanf
が誤って文字列定数に書き込みを行なうとするからである。
fscanf
と scanf
についても同様である。
これらの問題を解決する最も良い方法は、プログラムを変更して、
文字列定数の代わりに、char
の配列変数を使い、その文字列定数を
配列変数の初期化文字列として使うことである。
だが、この方法が不可能な場合、‘-fwritable-strings’ オプションを
指定すると、GCC は、他の多くの C コンパイラがやっているのと同じ方法で
文字列定数を扱う。
特に、‘-traditional’ を指定しても同じ効果が得られる。
-2147483648
は正の数である。
これは、2147483648 が int
型に収まらないため、
(ANSI C の規則に従って)そのデータ型が unsigned long int
に
なるためである。この値の符号を反転させると、再び 2147483648 になる。
#define foo(a) "a" |
の出力は、引数 a がなんであれ、"a"
となる。
オプション ‘-traditional’ を指定すると、GCC は、 特にこのようなケースを旧来の非ANSIの方式で取り扱う。
setjmp
と longjmp
を使っている場合は、
有効なままであると保証される自動変数は、volatile
宣言されたもの
だけである。
これは、自動的なレジスタ割当の結果である。
次の関数を考えてみよう。
jmp_buf j;
foo ()
{
int a, b;
a = fun1 ();
if (setjmp (j))
return a;
a = fun2 ();
/* |
ここでは、longjmp
が発生したときに、a
に
その最初の値がリストアされることもあるし、されないこともある。
a
がレジスタに割り当てられていれば、その最初の値がリストアされる。
そうでない場合は、最後に格納された値を保持しつづける。
‘-W’ オプションを ‘-O’ オプションと組み合わせて使用すると、 GCC がこのような問題が起こりうると考えた場合に警告が出る。
‘-traditional’ オプションを指定すると、GNU C は、
setjmp
を読んでいる関数内では、デフォルトでは、
変数をレジスタではなくスタックに置くようにする。
この結果、旧来の C コンパイラに見られる動作になる。
foobar ( #define luser hack) |
ANSI C は、このような構文を許していない。 ‘-traditional’ を指定したときにこの構文をサポートするのは、 意味のあることかもしれないが、実装するには手間がかかり過ぎる。
他の C コンパイラの中には、extern
宣言は、
たとえそれがあるブロック内にあっても、そのファイルの残り全体に
作用するものがある。
オプション ‘-traditional’ を指定すると、GNU C は、
旧来のコンパイラのように、全ての extern
宣言をグローバルとして
扱う。
long
等を typedef 名と組み合わせて、
以下のようにすることができた。
typedef int foo; typedef long foo bar; |
ANSI C では、これは許されない。long
やその他の型修飾子は
明示的な int
を必要とする。
この規準は、C コードではなくて Bison の文法規則中に表されているので、
‘-traditional’ オプションでは、この動作を変えることはできない。
#if 0 You can't expect this to work. #endif |
この様な問題を解決する最善の方法は、テキストを ‘/*…*/’ で 区切られた、本当のコメントの中に入れることである。 だが、‘-traditional’ でもこのエラーメッセージを抑止することができる。
time
の
宣言が入っていなかったので、これが何を返すように宣言しても問題に
なることはなかった。
だが、ANSI C のヘッダを入れているシステムでは、time
は
time_t
を返すように宣言されており、もし、これが long
と
同じでない場合は、‘long time ();’ は間違いである。
これを解決するには、time
の戻り値型として time_t
を
使うようにプログラムを変更することである。
float
を返す関数をコンパイルするとき、PCC だとそれを double に
変換する。GCC は実際にそのまま float
を返す。
PCC との互換性を考えるなら、その関数は double
を返すように
宣言すべきである。意図することと同じことを書いたほうが良いという事である。
GCC で使われる方法は以下の通り。
1、2、4、8 バイトの大きさの構造体や共用体は、スカラと同様に
返される。それ以外の大きさの構造体や共用体は全て、呼び出し側が
提供するアドレスに格納される(普通は特別な固定レジスタに入ってくるが、
機種によってはスタックで和和されるものもある)。
マシン記述マクロ STRUCT_VALUE
と STRUCT_INCOMING_VALUE
が、このアドレスを渡す場所を GCC に指示する。
対照的に、多くのターゲット機種上の PCC は、任意の大きさの構造体と 共用体を返すのに、静的な格納領域にデータをコピーし、その領域のアドレスを あたかもポインタちであるかのように返すことで行なう。 呼び出し側は、データをそのメモリ領域から、値を必要とする場所に コピーしなければならない。GCC は、この方法は遅く、再入可能でないので 採用していない。
新しめの機種の中には、PCC が全ての構造体と共用体を返すのに再入可能な 規約を使っているものもある。これらの機種の多くで GCC は、 メモリ中の構造体と共用体を返すのに、互換性のある規約を使っているが、 なお小さな構造体と共用体についてはレジスタに入れて返している。
GCC に全ての構造体と共用体について互換性のある規約を使うように 指示するには、‘-fpcc-struct-return ’オプションを指定する。
前処理トークンは、それが一個の数字で始まっており、その後に 英文字、アンダースコア、数字、ピリオド、‘e+’、‘e-’、 ‘E+’、‘E-’ が続くなら、前処理数値である。
上のようなプログラムの断片を有効にするには、マイナス記号の前に空白を 置くことである。この空白により、前処理数値が終わる。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated
using texi2html 1.78.