43

既存のCコードベースをC++コンパイラでコンパイルする場合、どのような問題が発生すると予想されますか?たとえば、列挙型の値に整数を割り当てることはC ++では失敗すると思いますが、Cでは(少し厄介な場合は)合法です。

すべてのCファイルをでラップしない場合extern C { ... }、予想外の場所で名前マングリングを実行しますか?私が本当にこれをすべきではない理由はありますか?

背景として、Cで記述された非常に大規模なコードベースがあります。数年間、C ++を介して自然に発生すること(たとえば、自作の継承)を実行するためにフープを飛び越えてきました。C ++への移行を開始したいと思いますが、段階的に進めていきます。CORBAのようなフレームワークでそれをサポートし、C++が提供するより自然なアプローチを利用するためにモジュールをリファクタリングします。

4

8 に答える 8

39

私は一度このようなことをしました。問題の主な原因は、ご想像のとおり、C++は型に関してより厳密であるということでした。void*が他のタイプのポインターと混合されているキャストを追加する必要があります。メモリの割り当てのように:

Foo *foo;
foo = malloc(sizeof(*foo));

上記は典型的なCコードですが、C++でキャストする必要があります。

Foo *foo;
foo = (Foo*)malloc(sizeof(*foo));

C ++には、「class」、「and」、「bool」、「catch」、「delete」、「explicit」、「mutable」、「namespace」、「new」、「operator」などの新しい予約語があります。 「または」、「private」、「protected」、「friend」など。たとえば、これらを変数名として使用することはできません。

上記は、C++コンパイラで古いCコードをコンパイルするときにおそらく最も一般的な問題です。非互換性の完全なリストについては、ISOCとISOC++の間の非互換性を参照してください。

名前のマングリングについても質問します。extern "C"ラッパーがない場合、C++コンパイラはシンボルマングルします。C ++コンパイラのみを使用し、ライブラリからシンボルをプルするためにdlsym()などに依存しない限り、問題はありません。

于 2009-05-14T04:29:56.410 に答える
26

すべての非互換性の非常に詳細なリストについては、 ISOCとISOC++の間の非互換性を参照してください。コンパイラエラーですぐに現れないものを含め、多くの微妙な問題があります。たとえば、問題になる可能性のある問題の1つは、文字定数のサイズです。

// In C, prints 4.  In C++, prints 1
printf("%d\n", sizeof('A'));
于 2009-05-14T04:19:52.410 に答える
10

すべてのCファイルを「externC{...}」でラップしないと、予想外の場所で名前マングリングが発生しますか?

CとC++をリンクしようとすると、それはあなたを噛みます。

私は以下を含む多くのヘッダーファイルを書きました:

#ifdef __cplusplus
    extern "C" {
#endif

// rest of file

#ifdef __cplusplus
    }
#endif

しばらくすると、既存のマルチインクルードボイラープレートにマージされ、表示されなくなります。ただし、配置する場所には注意する必要があります。通常は、ヘッダーに含まれるものの後に属します。

私が本当にこれをすべきではない理由はありますか?

CとC++を組み合わせるつもりがないことが確実にわかっている場合は、私が知っているようにそれを行う理由はありません。ただし、説明する段階的な移行では、CコンポーネントとC++コンポーネントの両方で使用する必要のある公開されたインターフェイスを備えたものには不可欠です。

これを行わない大きな理由は、関数のオーバーロードを防ぐためです(少なくともこれらのヘッダーでは)。すべてのコードをC++に移行し、それを維持/リファクタリング/拡張し始めたら、それを実行したいと思うかもしれません。

于 2009-05-14T10:57:05.683 に答える
5

一般的に、問題はまったく発生しません。はい、CとC ++の間にはいくつかの非互換性がありますが、修正するのが非常に簡単な上記のmallocキャストを除いて、それほど頻繁には発生しないようです。

次のオープンソースCライブラリをC++として正常にコンパイルして使用しました。

  • ExpatXMLパーサー
  • FreeType2フォントラスタライザー
  • libjpeg:JPEG画像を処理します
  • libpng:PNG画像を処理します
  • Zlib圧縮ライブラリ

最も難しかったのは、名前空間ラッパーを追加することでした。これは主に、コードの奥深くに埋め込まれた#includeステートメントが原因で、C++名前空間の外部にある必要がありました。

なぜ私はこれをしたのですか?私は人々が自分のアプリに直接リンクしていた商用ライブラリを販売しているからです。また、アプリが他のバージョンのExpat、FreeTypeなどにリンクされていることもありました。これにより、multiply-defined-symbolエラーが発生しました。最もクリーンな方法は、ライブラリ内のすべてを移動して、名前空間に非表示にすることでした。

しかし、私が使用しているすべてのオープンソースライブラリでそれを行ったわけではありません。まだ競合を引き起こしていないものもあり、問題を解決するのは非常に面倒ですが、私はそれらを修正することに取り掛かっていません。興味深い例外はSQLiteで、C++でコンパイルできませんでした。そこで、外部から見えるすべてのシンボルにプレフィックス(製品の名前)を追加して、大規模な検索と置換を行いました。それは私のクライアントの問題を解決しました。

于 2015-12-16T16:10:31.797 に答える
3

別の例:C ++にはintからenumへの暗黙の変換はありませんが、Cにはあります。本当にC ++で実行する場合は、キャストが必要になります。

于 2009-05-14T05:23:20.433 に答える
2

MSVCを使用する前にこれを実行しましたが、MSVCを使用する場合の適切な戦略は次のとおりです。

  1. 個々のファイルをCPPとしてビルドするように設定します。これにより、CPPコンパイラに段階的に移行できます。
  2. ctrl + f7を使用してファイルごとに作業し、その1つのファイルを作成します。
  3. すべてのmallocをキャストするのではなく、代わりにテンプレートバージョンを作成できます

foo =(Foo *)malloc(sizeof(* foo));

になります

foo = malloc<Foo>();

そしてもちろん、Foo+nバイトが必要な場合は過負荷になる可能性があります

また、可能な場合はメモリ割り当てを切り替えてRAIIを使用することをお勧めします。一部の関数は非常に複雑であるため、RAIIへの切り替えはリスクが高すぎることがわかりました。ほとんどの場合、それは簡単に実行できます。

于 2014-05-21T18:55:25.203 に答える
1

C ++はより厳密な型チェックを備えているため、malloc / realloc/callocへの各呼び出しにキャストを追加する必要がある場合があります。

于 2009-05-14T06:47:27.767 に答える
-2

C++コンパイラでコンパイルしてみてください。

typedef enum{ false = 0, true = 1} bool;
于 2016-04-19T06:12:49.453 に答える