web-dev-qa-db-ja.com

C89 / C90、C99およびC11の互換性

私はちょうど読んだ: Cウィキペディアエントリ 。私の知る限り、広く使用されているCには、C89、C99、C11の3つのバージョンがあります。私の質問は、異なるバージョンのソースコードの互換性に関するものです。プログラムを作成し(最新バージョンであるためC11で)、C89で作成されたライブラリをインポートするとします。 C11仕様に従ってすべてのファイルをコンパイルするときに、これら2つのバージョンは正しく連携しますか?

質問1:Cの新しいバージョン、つまりC99、C11は古いCバージョンのスーパーセットですか?スーパーセットとは、古いコードはエラーなしでコンパイルされ、新しいC仕様に従ってコンパイルされた場合も同じ意味です。

// C89とC99では意味が異なることを読みました。この機能とは別に、C89のC99およびC11スーパーセットはありますか?

質問1の答えが「いいえ」の場合、さらに2つの質問があります。

  1. 古いコードを新しいバージョンに「移植」する方法は?この手順を説明するドキュメントはありますか?

  2. C89またはC99またはC11を使用する方が良いですか?

よろしくお願いします。

[〜#〜] edit [〜#〜]:ISOCをC89に変更しました。

11
Michael S

新しいバージョンのC、つまり古いCバージョンのC99、C11スーパーセットですか?

大きくても微妙でも、多くの違いがあります。ほとんどの変更は、新しい機能とライブラリの追加でした。 C99とC11はC90のスーパーセットではありませんが、下位互換性を確保するために多大な努力が払われました。ただし、C11はほとんどがC99のスーパーセットです。

コードの記述が不十分な場合、C90から移植すると、さらに古いコードが破損する可能性があります。特に、さまざまな形式の「暗黙のint」および暗黙の関数宣言は、C99の言語から禁止されました。 C11はgets関数を禁止しました。

変更の完全なリストは、 pdf のC11ドラフトページ13にあります。ここで、「第3版」はC11を指し、「第2版」はC99を指します。

古いコードを新しいバージョンに「移植」する方法は?この手順を説明するドキュメントはありますか?

私はそのような文書については知りません。良いコードがあれば、移植は簡単です。コードが腐っている場合、移植は苦痛になります。実際の移植手順については、C99とC11の基本を知っていれば簡単なので、C99/C11に対応する信頼できる学習ソースを見つけるのが最善の策です。

C99からC11への移植は簡単です。

C89またはC99またはC11を使用する方が良いですか?

現在の標準であるC11を使用するのが最善です。 C99とC11には両方とも、さまざまな「言語バグ修正」が含まれ、新しい便利な機能が導入されました。

9
Lundin

ほとんどの場合、後のバージョンは前のバージョンのスーパーセットです。識別子としてrestrictを使用しようとするC89コードは、C99が同じスペルの予約語を追加することで壊れますが、いくつかのコーナーケースを悪用するように考案されたコードがパーサーは2つの言語で異なる方法で処理され、それらのほとんどは重要ではない可能性があります。

ただし、より重要な問題は、メモリエイリアシングに関係しています。 C89には、特定のオブジェクトへのアクセスに使用できるポインターのタイプを制限するルールが含まれています。ルールは、malloc()のような関数を、それによって作成されたオブジェクトに記述どおりに適用すると役に立たなくなるため、ほとんどのプログラマーとコンパイラーの作成者は、限られた場合にのみルールを適用するものとして扱いました(C89が広く受け入れられたとは思えません)。人々ルールが狭く適用されるとは信じていませんでした)。 C99はルールを「明確化」すると主張しましたが、その新しいルールは、古いルールの同時解釈よりも事実上はるかに広範であり、C89の一般的な解釈の下で動作を定義していたであろう多くのコード、さらにはC89の下で明確に定義されていたはずですが、実用的なC99に相当するものはありません。

たとえば、C89では、memcpyを使用して、任意のタイプのオブジェクトに関連付けられたビットパターンを、同じサイズの他のタイプのオブジェクトにコピーできます。そのビットパターンが有効なものを表す場合は、宛先タイプの値。 C99は、memcpyを使用してタイプTのオブジェクトを、タイプが宣言されていないストレージ(たとえば、mallocから返されたストレージ)にコピーする場合にコンパイラが任意の方法で動作できるようにする言語を追加しました。その後、元のオブジェクトのビットパターンが新しい型で有効な意味を持つ場合でも、Tとエイリアス互換ではない型のオブジェクトとして読み取られます。さらに、memcpyに適用されるルールは、オブジェクトが文字型の配列としてコピーされる場合にも適用されます-それが何を意味するのかを正確に明確にすることなく-したがって、C89に一致する動作を実現するためにコードが何をする必要があるかが正確に明確ではありませんmemcpy

多くのコンパイラでは、このような問題は、コマンドラインに-fno-strict-aliasingオプションを追加することで解決できます。コンパイラの作成者は、実装する予定の標準に関係なく同じメモリセマンティクスを使用することが多いため、C89モードを指定するだけでは不十分な場合があることに注意してください。

1
supercat

Cの新しいバージョンは、古いバージョンの厳密なスーパーセットではありません。

一般的に、この種の問題は、コンパイラをアップグレードするか、コンパイラベンダーを切り替えるときにのみ発生します。このイベントに対処するには、コードを少し変更することを計画する必要があります。多くの場合、新しいコンパイラは、新しいC標準を適用することによって発生した可能性のある小さな非互換性に加えて、古いコンパイラによって診断されないままにされた問題をキャッチします。

決定できる場合、使用するのに最適な標準は、コンパイラーが最適にサポートする標準です。

C11ウィキペディアの記事 には、C99との違いについての長い説明があります。

0
jxh

一般に、標準の新しいバージョンには下位互換性があります。

そうでない場合は、さまざまな標準を使用して、さまざまな.cファイルをさまざまな.oファイルにコンパイルし、それらをリンクすることができます。それはうまくいきます。

通常、新しいコードで利用可能な最新の標準を使用する必要があります。簡単な場合は、上記のハッキーなソリューションを使用する代わりに、新しい標準が壊れているコードを修正してください。

[〜#〜] edit [〜#〜]:未定義の可能性のある動作を扱っている場合を除きます。

0
Paul Stelian