web-dev-qa-db-ja.com

C ++からC関数を呼び出すときにCスタイルのキャストを使用できますか?

このサイト と他の場所の両方を読んだので、C++の推奨プログラミングスタイルはCスタイルのキャストの使用を避け、C++スタイルのstatic_castdynamic_castreinterpret_castconst_cast。この推奨の理由は、一般に、(1)C++キャストはより具体的で意味が限定されているためより安全であり、(2)良いC++コードで頻繁に使用するべきではないため、意図的に冗長で見苦しいものになります。ただし、私の推論は、私のC++コードからC関数を呼び出すことに関してはあまり意味がありません。

私のC++プロジェクトでは、ネットワーク操作用のPOSIXソケットライブラリなど、Cインターフェイスのみを備えたOSレベルのライブラリを呼び出さざるを得ません。これらのC関数は、多くの場合、呼び出し元がいくつかのポインターキャストを行うことを期待しており、C++スタイルのキャストのみを使用すると、コードが不格好で冗長になります。たとえば、私のネットワークコードには、次のような関数呼び出しが散らばっています。

std::size_t message_size;
ssize_t bytes_read = recv(fd, reinterpret_cast<char*>(&message_size), sizeof(message_size), MSG_WAITALL);

C++キャストを使用しても安全性は得られません(reinterpret_castは、実際にはCスタイルのキャストよりもコンパイル時のチェックを追加しません)。コードの醜さから問題が発生することはありません。キャストせずにソケット関数を使用する方法はありません。

CとC++の間のインターフェースの不一致を考慮して、キャストが必要なC関数を呼び出すときにCスタイルのキャストを使用するのは妥当でしょうか?または、Cスタイルのキャストは常に悪い習慣であり、C関数を呼び出す必要がある場合は、余分なコードの膨張を受け入れる必要がありますか?

4
Edward

C関数の呼び出しの冗長性がコードを乱雑にするのを防ぐのは簡単です。それらをラップしてください。たとえば、recvの場合、これを行うことができます。

template <typename T>
ssize_t recv(int fd, T& data) {
  return ::recv(fd, reinterpret_cast<char*>(&data), sizeof(data), MSG_WAITALL);
}

これを改善することができます。 static_asserting Tは簡単にコピー可能であるか、他の必要なプロパティがあります。

コード全体でC recvの代わりにこの関数を使用すると、乱雑さが減り、安全性が向上します(データ型とそのサイズを誤って一致させることはできません)。

同時に、まだC++スタイルのキャストを使用しているため、誤ってconstnessをキャストしてしまうのを防ぐことができます。

8
Sebastian Redl

標準は、Cスタイルのキャストがどのように機能するかを説明しています(N4296)。

5.4/4:によって実行される変換

  • _const_cast_、
  • _static_cast_、
  • _static_cast_に続く_const_cast_、
  • _reinterpret_cast_、または
  • _reinterpret_cast_に続く_const_cast_、

明示的な型変換のキャスト表記を使用して実行できます。 (...)

詳細を入力せずに、残りの段落では、Cキャストが、派生クラスへのポインターの存在下で_static_cast_に適用されるいくつかの制約を緩和することも説明しています。このリラックスした態度が、C++コードでは使用しないことが推奨される理由の1つです。

あなたの場合、_(char*)&message_size_を使用すると、コンパイラによってreinterpret_cast<char*>(&message_size)が生成されます。したがって、_reinterpret_cast_を直接使用しても何も失うことはありません。

Bjarne Stroustrupは、他のいくつかの理由を挙げています。なぜ彼の著書「C++の設計と進化」でC++キャストを優先する必要があるのでしょうか。

要約すると、古いスタイルのキャスト:

  1. 理解するのに問題がある:それらはいくつかの弱く関連する操作に対して単一の表記を提供する
  2. エラーが発生しやすい:ほとんどすべてのタイプの組み合わせ[つまりソースタイプとターゲットタイプ]には法的な解釈があります
  3. コード内で見つけにくく、シンプルなツールでは見つけにくい
  4. CおよびC++文法を複雑にする

新しいキャスト演算子は、古いキャスト機能の分類を表します。

もちろん、特別なケースでは、ポイント1、2、4は実際の問題ではありません。それでも、新しいスタイルを使用すると、ポイント3の利点が得られ、C++キャストで一般的に使用されているより高い精度に慣れることができます。

一方、私見では、Cライブラリとの相互運用性をコード内の唯一のハイライトに限定して使用する場合でも、C構文を使用しても衝撃はありません。

4
Christophe