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

我们有一个微 Controller 和一个外部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函数以在整个应用程序中更改它们。

我考虑过的解决方案之一是:
#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标准的偏差,而仅在该特定位置使用该偏差,还是有更好的解决方案来解决这个问题?

最佳答案

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

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

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

  • 要避免出现填充/对齐问题,您可以编写类似以下内容的内容:
    COMPILE_TIME_ASSERT( (sizeof(union_member1)+sizeof(union_member2)+...) ==
                         sizeof(union_type) );
    

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

    进一步的评论:

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



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

    关于c - 关于MISRA中有关C的 union 的想法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11882932/

    10-12 17:17