6

ミスラはすべての組合を禁止すると言っている。また、徹底的に議論され文書化されている限り、逸脱は許容されることも知っています。

統計データ(イベント/エラーログ、パラメーター設定など)を保存するためのマイクロコントローラーと外部EEPROMがあります。

イベントログは、約80以上のイベントカウンターで構成され、一部は8、16、および32ビット(すべて署名なし)です。パラメータストレージは約200個のパラメータで構成され、8、16、および32ビット値(符号なし)と混合されます。

すべてのコードをMISRAに準拠するように書き直しています。これらの値は以前に定義されていたため、次のようになります。

typedef struct
{
  U16BIT eventLogVar1;
  U32BIT eventLogVar2;
  U8BIT  eventLogVar3;
  U8BIT  eventLogVar4;
  U32BIT eventLogVar5;
} EVENT_LOG;

typedef union
{
  EVENT_LOG log;
  U8BIT     array[sizeof(EVENT_LOG)];
} ELOG;

ELOG log;

現在、これは実際にはMISRAに準拠していません。パラメータログについても同様です。ただし、これはeepromからの読み取りと書き込みを行う最も簡単な方法です。これは、eepromから読み取り/書き込みを行うには、配列を介して読み取り/書き込みを行う必要があるためです。

他にも、破ることが許されていないルールがいくつかあります。グローバル(外部)変数はありません(ヘッダーファイルを介して)。すべてのローカル変数は、必要に応じて、get/set関数を介してのみアクセスする必要があります。

これは、これらすべてのパラメーターを完全に書き出す必要がある場合、アプリケーション全体でそれらを変更するために、それぞれが独自のget/set関数を取得する必要があることを意味します。

私が考えた解決策の1つは次のとおりでした:

#ifdef EITHER
enum
{
    eventLogVar1 = 0; /* 00 */
    pad01;            /* 01 */
    eventLogVar2;     /* 02 */
    pad03;            /* 03 */
    pad04;            /* 04 */
    pad05;            /* 05 */
    eventLogVar3;     /* 06 */
    eventLogVar4;     /* 07 */
    eventLogVar5;     /* 08 */
    pad09;            /* 09 */
    pad10;            /* 10 */
    pad11;            /* 11 */
}
#else /* OR */
#define eventLogVar1 0 /* 2 bytes */
#define eventLogVar2 2 /* 4 bytes */
#define eventLogVar3 6 /* 1 byte  */
#define eventLogVar4 7 /* 1 byte  */
#define eventLogVar5 8 /* 4 bytes */
#endif
#define eventLogLastLength 4

U8BIT eventLog[eventLogVar5 + eventLogLastLength];

U8BIT getU8BIT(U8BIT index){}
U16BIT getU16BIT(U8BIT index){}
U32BIT getU32BIT(U8BIT index){}

void setU8BIT(U8BIT index, U8BIT val){}  
void setU16BIT(U8BIT index, U16BIT val){}
void setU32BIT(U8BIT index, U32BIT val){}

ただし、値が追加または削除された場合、これは面倒なリファクタリングを引き起こします。また、特定のタイプ(センサーなど)を多かれ少なかれ使用する場合、長さの定義によって変更できる配列型の値を使用できない(いくつかあります)ことも意味します。


この特定の問題についてどう思いますか。この特定のケースでMISRA標準からの逸脱を文書化し、この特定の場所でのみこの逸脱を使用する方がよいでしょうか、それともこの問題に対するより良い解決策がありますか?

4

3 に答える 3

6

ログユニオンは、まさに使用を許可されるべき種類のユニオンであり、データパッキングを実行します。これは、MISRAが許容可能な偏差であると明示的に示しているため、偏差が実行する必要があります。MISRAを使用するほとんどすべての人が、このようにこのルールから逸脱しています。(これはかなり悪いルールであり、次のMISRAバージョンでアドバイザリに降格されるか、完全に削除されるようです。)

ただし、次のことを文書化する必要があります。

  • バイトのパディングと配置が問題になるかどうか。
  • コードを移植可能にする必要がある場合、エンディアンが問題になる可能性があるかどうか。

パディング/アライメントの問題を回避するには、次のように記述します。

COMPILE_TIME_ASSERT( (sizeof(union_member1)+sizeof(union_member2)+...) ==
                     sizeof(union_type) );

ここで、COMPILE_TIME_ASSERTは、正の値が渡されない場合にコンパイラエラーを生成するマクロです。これにより、構造体/共用体のパディングが存在しなくなります。


さらなるコメント:

enumには独自の欠陥がいくつかあるため、enumは悪い解決策です。enum型の変数には実装定義のサイズがあり、列挙型定数には型signedintがあります。これは、暗黙的な型変換に関するMISRAルールと衝突し、多数の型キャストを追加する必要があります。

すべてのローカル変数は、必要に応じて、get/set関数を介してのみアクセスする必要があります。

またstatic、範囲を縮小するように宣言する必要があります。スニペットから、これを行わないことに気づきました。staticMISRA:20048.11によって実施されます。

于 2012-08-10T12:00:46.723 に答える
5

ユニオンは、適切に使用すると非常に便利な構成になります。

また、巧妙なことをしようとすると、未定義の動作が発生します。MISRAガイドラインが防止しようとしている未定義の動作を防止するためです。しかし、規則(MISRA C:2004の18.2)でさえ、組合が役立つ場合を示しています。

あなたが与える例はそのような有用な状況の1つであり、まさにMISRA逸脱手順がそこにあるような状況です。


免責事項:私はMISRA Cワーキンググループのメンバーですが、個人的な立場で投稿しています。私の見解は、公式のMISRAポリシーと見なされるべきではありません。

于 2012-11-08T07:32:34.363 に答える
2

MISRAはmemcpyについて何と言っていますか?ユニオンを使用する代わりに、EVENT_LOGを使用してみませんか?EEPROMとの間でシリアル化する場合は、次のような一時配列を使用します。

EVENT_LOG log;

U8BIT array[sizeof(EVENT_LOG)];
// populate array

memcpy(&log, array, sizeof(EVENT_LOG));

// do similar thing when writing to eeprom

ユニオンはデータとシリアル化形式を一緒に混合しますが、関数がより適している可能性がありますか?

void EVENT_LOG_write_to_eeprom(const EVENT_LOG*);
void EVENT_LOG_read_from_eeprom(EVENT_LOG*);
于 2012-08-09T12:23:36.297 に答える