MISRAが以下のコードでこのエラーを発生させないようにするにはどうすればよいですか?(unit16_t)でキャストしてみました。しかし、その後、明示的な変換は許可されませんでした。
複雑な式で、基になるMISRAタイプ「unsignedchar」から「unsignedint」への不正な暗黙の変換(MISRA C 2004ルール10.1)
uint8_tレート=3U; uint8_tパーセンテージ=130U; uint16_tbasic_units=レート*パーセンテージ;
問題は、「int」と入力する整数拡張によって、レートとパーセンテージの両方がサイレントにプロモートされることです。したがって、乗算は符号付き型で実行されます。
MISRA互換コードは、コードを次のように書き直すことです。
uint16_t basic_units = (uint16_t)rate * (uint16_t)percentage;
または、MISRAが提案するように、式の結果をその「基になる型」にすぐに型キャストします。
uint16_t basic_units = (uint8_t)(rate * percentage);
編集:明確化が続きます。
ISO 9899:1999 6.3.1.1 2
intが元の型のすべての値を表すことができる場合、値はintに変換されます。それ以外の場合は、unsignedintに変換されます。これらは整数プロモーションと呼ばれます。
MISRA-Cからの有益なテキスト:
MISRA-C:2004 6.10.3危険な型変換:
/-/
-算術演算の符号の変更:汎整数拡張では、多くの場合、2つの符号なしオペランドが生成され、 (signed)int型の結果が生成されます。たとえば、2つの16ビット符号なしオペランドを追加すると、intが32ビットの場合は符号付き32ビットの結果が得られますが、intが16ビットの場合は符号なし16ビットの結果が得られます。
上記の2行目がMISRAを満たすかどうかは実際にはわかりませんが、MISRA 10.1と10.5を混同した可能性があります。後者では、基になる型への即時キャストが強制されますが、特定のビット演算子の場合のみです。 。
LDRA静的コード分析を使用して両方の行をテストしましたが、文句はありませんでしたが(ただし、関連性のない誤った警告が表示されます)、LDRAもMISRA-Cで非常にパフォーマンスが低下します。
とにかく、元の質問の問題は、 intがuint8_tのすべての値を表すことができるため、レートとパーセンテージの両方が整数拡張によって符号付きのint型に暗黙的に変換されることです。だからそれは
uint16_t basic units = (int)rate * (int)percentage.
これを防ぐには、明示的に型キャストする必要があります。もっと考えてみたら、上の2行の1行目に行きます。
MISRAルールは、計算に使用される「基になるタイプ」が結果のタイプと同じであることを確認しようとしています。これを実現するために、オペランドの1つまたは両方をキャストできます。
uint8_t rate = 3U;
uint8_t percentage = 130U;
uint16_t basic_units = (uint16_t)rate * percentage;
32ビットアーキテクチャでは、キャストなしの結果は問題ありませんが、次のことを考慮してください。
uint32_t rate = ...;
uint32_t percentage = ...;
uint64_t basic_units = rate * percentage;
32ビットアーキテクチャでは、ターゲットタイプが64ビット幅であっても、操作は32ビットで実行されます。レートとパーセンテージが十分に大きい場合、これにより操作が32ビットでラップされる可能性があり、ターゲットタイプに適合するデータが失われます。
MISRAルールは、ターゲットプラットフォームのタイプのサイズに関係なく、コードをより安全にしようとしています。
暗黙の変換は、乗算のために、乗算の前に実行されます。乗算がツールをシャットダウンする直前の明示的な変換かもしれません
uint16_t basic_units = (unsigned)rate * (unsigned)percentage;
結果の値は、警告なしunsigned
で暗黙的に変換する必要があります。uint16_t
ツールがこれについてもPITAになることを選択した場合は、別の明示的な変換を試してください。
uint16_t basic_units = (uint16_t)((unsigned)rate * (unsigned)percentage);
Cスタイルのキャストを使用してオペランドをキャストしようとすると、ツールに何か別の不満を与える可能性があります。したがって、これを行う代わりに:
uint16_t basic_units = (uint16_t)rate * (uint16_t)percentage;
これを行う必要があるかもしれません:
uint16_t basic_units = static_cast<uint16_t>(rate) * static_cast<uint16_t>(percentage);