米斯拉说禁止所有工会。我也知道,只要对偏差进行了彻底的讨论和记录,就可以允许它们。
我们有一个微控制器和一个外部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标准的偏差,而仅在此特定位置使用该偏差,还是有解决此问题的更好方法?
您的日志联合正是您应被允许使用的联合类型,它正在做的是数据打包,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执行。
如果使用得当,联合是一个非常有用的结构。
当人们试图用它们做聪明的事情时,它们也会有未定义的行为。这是为了防止 MISRA 指南试图防止的未定义行为。但即使是规则(MISRA C:2004 中的 18.2)也给出了联合有用的情况。
您给出的示例就是这样一种有用的情况,并且正是 MISRA 偏差程序适用的那种情况。
免责声明:我是 MISRA C 工作组的成员,但我以个人身份发帖。我的观点不应被视为官方的MISRA 政策。