关于MISRA中C工会的想法

Daa*_*mer 5 c misra

米斯拉说禁止所有工会。我也知道,只要对偏差进行了彻底的讨论和记录,就可以允许它们。

我们有一个微控制器和一个外部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;
Run Code Online (Sandbox Code Playgroud)

现在这不是真的符合MISRA。参数日志也是如此。但这是从eeprom读取和写入的最简单方法,因为我只需要通过阵列读取/写入即可从eeprom读取/写入。

我们还有其他一些规则是我们绝对不允许违反的。没有全局(外部)变量(通过头文件)。如果需要,所有局部变量只能通过get / set函数访问。

这意味着,如果我们需要完全写出所有这些参数,则每个参数都应获得自己的get / set函数以在整个应用程序中更改它们。

我考虑过的解决方案之一是:

#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){}
Run Code Online (Sandbox Code Playgroud)

但是,如果添加或删除值,这将带来繁琐的重构。这也意味着不能使用类型数组的值(有一些),如果使用某种或多种某种类型的传感器,则可以通过定义长度来更改它。


您对这个特定问题有何看法?在这种特定情况下,我/我们会更好地记录与MISRA标准的偏差,而仅在此特定位置使用该偏差,还是有解决此问题的更好方法?

Lun*_*din 5

您的日志联合正是您应被允许使用的联合类型,它正在做的是数据打包,MISRA明确声明这是可以接受的偏差,所以偏差是您应该采取的措施。几乎每个使用MISRA的人都以这种方式背离了该规则。(这是一个非常糟糕的规则,看起来它会在下一个MISRA版本中降级为通报或完全删除。)

但是您需要记录以下内容:

  • 填充字节和对齐方式是否会成为问题。
  • 如果代码需要可移植,是否持久性可能是个问题。

要避免出现填充/对齐问题,您可以编写以下内容:

COMPILE_TIME_ASSERT( (sizeof(union_member1)+sizeof(union_member2)+...) ==
                     sizeof(union_type) );
Run Code Online (Sandbox Code Playgroud)

其中COMPILE_TIME_ASSERT是某个宏,如果未传递正值,该宏将产生编译器错误。这样可以确保不存在结构/联合填充。


进一步的评论:

enum是一个不好的解决方案,因为它有许多缺陷:enum类型的变量具有实现定义的大小,而枚举常量的类型为int类型。这将与有关隐式类型转换的MISRA规则相冲突,您将不得不添加许多类型转换。

如果需要,所有局部变量只能通过get / set函数访问。

还需要声明它们static以缩小范围。我从您的摘要中注意到您没有这样做。static由MISRA:2004 8.11执行。


And*_*rew 5

如果使用得当,联合是一个非常有用的结构。

当人们试图用它们做聪明的事情时,它们也会有未定义的行为。这是为了防止 MISRA 指南试图防止的未定义行为。但即使是规则(MISRA C:2004 中的 18.2)也给出了联合有用的情况。

您给出的示例就是这样一种有用的情况,并且正是 MISRA 偏差程序适用的那种情况。


免责声明:我是 MISRA C 工作组的成员,但我以个人身份发帖。我的观点不应被视为官方的MISRA 政策。

  • 感谢您向我解释 MISRA 的官方政策。;-) (3认同)