5

次の例では:

bool bad_function()
{  
  char_t * ptr = 0;

  // MISRA doesn't complains here, it allows cast of char* to void* pointer
  void* p2 = ptr;

  // the following 2 MISRA violations are reported in each of the casts bellow (two per code line)
  // (1) Event misra_violation:     [Required] MISRA C++-2008 Rule 5-2-7 violation: An object with pointer type shall not be converted to an unrelated pointer type, either directly or indirectly
  // (1) Event misra_violation:     [Required] MISRA C++-2008 Rule 5-2-8 violation: An object with integer type or pointer to void type shall not be converted to an object with pointer type
  ptr = (char_t*) (p2); 
  ptr = static_cast<char_t*> (p2); 
  ptr = reinterpret_cast<char_t*> (p2); 

  return true;
}

MISRA 5-2-8 および 5-2-7 違反が報告されます。

この違反を削除するにはどうすればよいですか?

C++ の静的解析の経験がある人に助けてもらいたいです。数日前から、このばかげたルールに頭を悩ませています。

MISRA C++ 標準 (MISRA-Cpp-2008.pdf: ルール 5-2-7 (必須): ポインター型のオブジェクトは、直接的または間接的に、関連のないポインター型に変換してはなりません。

わかりましたが、たとえば、アドレスを に変換しchar*て で使用する必要がある多くのコードがありstd::ifstream、そのread(char* buffer, int length)関数はアドレスを ( ) に型キャストする必要がありますchar_t*。では、MISRA の担当者によると、キャストをまったく使用せずに C++ でプログラミングできるのはどうしてでしょうか? 標準では、どのようにポインタ変換を行う必要があるかについては述べていません。

私の製品コードでは、事前定義されたデータ構造のファイルからread with std:ifstreamを使用したファイル読み取り操作に問題があります。

if (file.read((char_t*)&info, (int32_t)sizeof(INFO)).gcount() != (int32_t)sizeof(INFO)
{
                LOG("ERROR: Couldn't read the file info header\n");
                res = GENERAL_FAILURE;
}

MISRAによるとどうすればいいのですか?

それで、何か解決策はありますか?

編集: Peter と QQ の回答はどちらも正しいです。プロジェクトが最終段階にある場合、MISRA は実際にキャストなしですべてを実行したいと考えているようです。次の 2 つのオプションがあります。

1 - MISRA の逸脱を 1 つずつ文書化し、キャストが OK である理由を説明し、これがどのようにテストされたかを説明します (QQ の提案)

2 - file.read() に char 型のバイト配列を使用し、ファイルの内容を安全に読み取った後、バイト配列をヘッダーの内容にキャストします。char* を int32_t にキャストすると、これをメンバーごとに 1 つずつ行う必要があります。再びルール 5-2-7 違反です。時にはそれはあまりにも多くの仕事です。

4

3 に答える 3

1

MISRA ルールの基本的な理由は、任意のポインター/アドレスを任意の非 void ポインターに変換すると、実際とは異なるオブジェクトであるかのようにそのアドレスを使用できるようになるためです。そのような場合、コンパイラは暗黙的な変換について文句を言います。型キャスト (または C++_cast演算子) を使用すると、コンパイルの不平が本質的に停止し、カウントできないほど多くの状況で、そのポインターを逆参照すると未定義の動作が発生します。

つまり、型変換を強制することで、潜在的な未定義の動作を導入し、コンパイラがその可能性を警告する可能性をすべてオフにします。MISRAはそれは悪い考えだと思います....コーディングの容易さの観点から考える多くのプログラマーが場合によってはそれを良い考えだと考えるという事実にもかかわらず.

MISRA チェックの哲学は、典型的なプログラマーほどプログラミングの容易さには関心がなく、未定義 (または実装定義または未指定など) の動作がすべてのチェックを通過し、コードが「害を及ぼす可能性があります。

file.read()問題は、実際のユースケースでは、(おそらく) という名前のデータ構造を正しく設定することに依存していることですinfo

if (file.read((char_t*)&info, (int32_t)sizeof(INFO)).gcount() != (int32_t)sizeof(INFO)
{
            LOG("ERROR: Couldn't read the file info header\n");
            res = GENERAL_FAILURE;
}

あなたがする必要があるのは、MISRA チェッカーに合格する有効なコードを提供するためにもう少し努力することです。何かのようなもの

std::streamsize size_to_read = whatever();
std::vector<char> buffer(size_to_read);  

if (file.read(&buffer[0], size_to_read) == size_to_read)
{
      //  use some rules to interpret contents of buffer (i.e. a protocol) and populate info
      // generally these rules will check that the data is in a valid form
      //   but not rely on doing any pointer type conversions
}
else
{
            LOG("ERROR: Couldn't read the file info header\n");
            res = GENERAL_FAILURE;
}

はい、単純に型変換を使用したり、バイナリの保存と構造体の読み取りを許可したりするよりも多くの作業が必要であることを認識しています。しかし、それらは休憩です。MISRA チェッカーを通過することは別として、このアプローチを正しく行えば、コードのビルドに使用されるコンパイラーにファイル形式が完全に依存しないなど、他の利点があります。あなたのコードは実装定義の数量 (構造体のメンバーのレイアウト、 の結果sizeof) に依存するため、コンパイラ A でビルドされた場合、コンパイラ B でビルドされたコードによって生成されたファイルを読み取ることができない場合があります。 MISRA 要件の共通のテーマは、実装定義の量に敏感な可能性がある動作を伴うコードを削減または排除することです。

注: また、最初の引数として を渡し、2 番目の引数として anchar_t *を渡します。どちらも実際には正しくありません。実際の引数はand型です (これは である必要はありませんが、 である必要はありません)。std::istream::read()int32_tchar *std::streamsizeint32_t

于 2015-12-14T13:11:05.257 に答える
0

freadは、ファイル入力用の完全に優れた C++ 関数でvoid*あり、MISRA が許可する を使用します。

また、ローカライズされた文字変換ロジックを介してすべてのデータを処理するのとは異なり、バイナリ データの読み取りにも適してfstreamいます (これは構成可能な iostream の「ファセット」ですが、標準ではノーオペレーションを実現するための移植可能な方法は定義されていません)。変換)。

fopen/の C スタイルはfclose、ファイルのクリーンアップを忘れる可能性があるため、C++ プログラムでは残念です。幸いなことstd::unique_ptrに、任意のポインタ型に RAII 機能を追加できるこれがあります。std::unique_ptr<FILE*, decltype(&fclose)>C++ で高速な例外セーフ バイナリ ファイル I/O を使用します。


注意: よくある誤解は、std::ios::binaryバイナリ ファイル I/O を与えるというものです。そうではありません。影響を受けるのは、改行変換と (一部のシステムでは) ファイルの終わりマーカーの処理だけですが、ファセット駆動の文字変換には影響しません。

于 2015-12-09T15:42:27.270 に答える