56

この質問は、Herb Sutter による投稿への返信によって引き起こされました。彼は、C99 コンパイラをサポート/作成せず、とにかく C++(11) 標準にある C(99) 機能を使用するという MS の決定について説明しました。

1 人のコメント投稿者は次のように答えました

(...) C は重要であり、少なくとも少しは注目に値します。

有効な C であるが有効な C++ ではない既存のコードがたくさんあります。そのコードは書き直されそうにない (...)

私は MS C++ でしかプログラミングしていないので、「純粋な」C についてはあまりよく知りません。一部の C99 コードが C++ コンパイラでそのままでは機能しない手がかり。

restrict私が知っているのは、C99 のみのキーワードであり、適用範囲が非常に狭いと思われることと、可変長配列について知っていることに注意してください(それらがどれほど広く普及しているか、または重要であるかはわかりません)。

また、重要なセマンティックの違いや落とし穴、つまり、 C++(11) でコンパイルされる C(99) コードがあるかどうかにも非常に興味がありますが、C++ コンパイラでは C コンパイラとは異なる動作をします。


クイック リンク: 回答からの外部リソース:

4

4 に答える 4

32

C99 と C11 には非常に優れた機能がたくさんあるだけでなく、長年 (C90 以前) 存在していた多くの非互換性があります。これらはすべて私の頭のてっぺんから外れています。

// Valid C
int *array = malloc(sizeof(*array) * n);

// Valid C and valid C++, extra typing, it's always extra typing...
int *array = (int *) malloc(sizeof(*array) * n);

// Valid C++
int *array = new int[n];

C99 は素晴らしいので、世界中の C プログラマーが使用する必要があります

C99 の新機能は、一般的なプログラミングにとって非常に便利です。VLA および VLArestrictは (私の意見では) 一般的な使用を対象としていませんが、主に FORTRAN および数値プログラマーを C に移行することを目的としています (ただしrestrict、自動ベクトル化には役立ちます)。を使用する準拠プログラムは、ファイルの先頭にいるrestrict場合でもまったく同じように動作するため (ただし、速度は遅くなる可能性があります) #define restrict、大したことではありません。VLA は実際には非常にまれなようです。

柔軟な配列メンバーは便利です。 これらは可変長配列と同じではないことに注意してください! 人々はこのトリックを何年も使用してきましたが、公式サポートにより入力が少なくなり、コンパイル時に定数を作成できるようになりました。(古い方法ではサイズ 1 の配列を使用していましたが、割り当てサイズを計算するのは本当に面倒です。)

struct lenstr {
    unsigned length;
    char data[];
};
// compile time constant
const struct lenstr hello = { 12, "hello, world" };

指定された初期化子。 多くのタイピングを節約します。

struct my_struct { int a; char *b; int c; const char *d; };
struct my_struct x = {
    .a = 15,
    .d = "hello"
    // implicitly sets b = NULL and c = 0
};
int hex_digits[256] = { ['0'] = 0, ['1'] = 1, ['2'] = 2, /* etc */ ['f'] = 15 };

inlineキーワードの動作は異なります。extern 宣言をそのユニットに追加することにより、インラインで宣言された関数の非インライン バージョンを取得する翻訳ユニットを選択できます。

複合リテラル。

struct point { float x; float y; };
struct point xy_from_polar(float r, float angle)
{
    return (struct point) { cosf(angle) * r, sinf(angle) * r };
}

このsnprintf関数は、おそらく C で最も有用なライブラリ関数のトップ 10 に入っています。C++ にないだけでなく、MSVC ランタイムは という関数しか提供して_snprintfいません。これは、文字列に NUL ターミネータを追加することが保証されていません。(snprintfこれは C++11 にありますが、MSVC C ランタイムにはまだ明らかに存在しません。)

匿名の構造体と共用体(C11、しかし GCC の拡張機能は永遠に) (匿名の共用体は明らかに C++03 にあり、C モードでは MSVC をサポートしていません):

struct my_value {
    int type;
    union {
        int as_int;
        double as_double;
    }; // no field name!
};

ご覧のとおり、これらの機能の多くは、入力の手間を省いたり (複合リテラル)、プログラムのデバッグを容易にしたり (柔軟な配列メンバー)、間違い (指定された初期化子/構造体フィールドの初期化の忘れ) を回避しやすくしたりします。これらは劇的な変化ではありません。

セマンティックの違いについては、エイリアシング ルールが異なると確信していますが、最近ではほとんどのコンパイラが十分に寛容になっているため、テスト ケースをどのように構築して実証するのかわかりません。誰もが到達する C と C++ の違いは古いsizeof('a')式です。C++ では常に 1 ですが、32 ビット C システムでは通常 4 です。しかし、とにかく誰も気にしませsizeof('a')ん。ただし、C99 標準には、既存のプラクティスを成文化する保証がいくつかあります。

次のコードを取ります。余分なストレージを無駄にすることなく、C でユニオン型を定義するための一般的なトリックを使用します。これは意味的に有効な C99 であり、意味的に疑わしい C++だと思います、間違っている可能性があります。

#define TAG_FUNKY_TOWN 5
struct object { int tag; };
struct funky_town { int tag; char *string; int i; };
void my_function(void)
{
    struct object *p = other_function();
    if (p->tag == TAG_FUNKY_TOWN) {
        struct funky_town *ft = (struct funky_town *) p;
        puts(ft->string);
    }
}

しかし、それは残念です。 MSVC コード ジェネレーターは優れていますが、C99 フロントエンドがないのは残念です。

于 2012-05-05T12:49:24.400 に答える
28

クリーンC(C90ではない)と呼ばれることもあるCとC ++の共通のサブセットから始める場合は、次の3種類の非互換性を考慮する必要があります。

  1. 合法的なCを違法なC++にする追加のC++機能

    この例としては、Cで識別子として使用できるC ++キーワードや、Cで暗黙的であるが、C++で明示的にキャストする必要がある変換があります。

    これがおそらく、MicrosoftがまだCフロントエンドを出荷している主な理由です。そうしないと、C++としてコンパイルされないレガシーコードを書き直す必要があります。

  2. C++の一部ではない追加のC機能

    C ++がフォークされた後、C言語は進化を止めませんでした。いくつかの例は、可変長配列、指定された初期化子、およびrestrictです。これらの機能は非常に便利ですが、C ++標準の一部ではなく、一部の機能はおそらく機能しません。

  3. CとC++の両方で使用できるが、セマンティクスが異なる機能

    この例は、constオブジェクトまたはinline関数のリンクです。

C99とC++98の間の非互換性のリストは、ここにあります(これは、Matによってすでに言及されています)。

C ++ 11とC11はいくつかの面で近づいていますが(可変長配列はC ++で利用可能になり、可変長配列はオプションのC言語機能になりました)、非互換性のリストも増えています(たとえば、CとautoC ++の型指定子)。

余談ですが、MicrosoftはC(最近のものではありません)を放棄する決定にいくらか熱心に取り組んでいますが、オープンソースコミュニティの誰も実際にそれについて何かをするための措置を講じていないことを私は知っています。 C-to-C ++コンパイラを介して最新のCの多くの機能を提供することは非常に可能です。特に、それらのいくつかを実装するのが簡単であると考える場合はそうです。これは、C99をサポートするComeau C /C++を使用して現在実際に可能です。

ただし、これは実際には差し迫った問題ではありません。個人的には、WindowsでGCCとClangを使用することに非常に慣れており、MSVCの独自の代替手段(Pelles CやIntelのコンパイラなど)もあります。

于 2012-05-05T12:56:24.290 に答える
2

C++11 標準の「C.1 C++ と ISO C」について言及します。そのドキュメントには、それぞれの違いとその開発への影響が一挙に記載されています。

于 2012-05-06T14:36:03.240 に答える
2

C++ では、共用体の 1 つのメンバーを設定し、別のメンバーの値にアクセスすることは未定義の動作ですが、C99 では未定義ではありません。

ウィキペディアのページにリストされている他の多くの違いがあります。

于 2012-05-05T15:05:15.997 に答える