为什么匿名枚举不符合 MISRA C 2012 规则 10.3 而命名枚举不符合?

Why does an anonymous enum fails MISRA C 2012 rule 10.3 and a named enum doesn't?

有问题:

我在使用此代码时遇到问题,因为未通过 MISRA C 2012 规则 10.3,其中规定:

The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category

代码是这样的:

typedef enum
{
   FLS_PROG_SUCCESS,
   FLS_PROG_FAIL,
   FLS_ERASE_SUCCESS2U,
   FLS_ERASE_FAIL,
   FLS_READ_SUCCESS,
   FLS_READ_FAIL,
   FLS_FORMAT_SUCCESS,
   FLS_FORMAT_FAIL
}FLS_JobResult_t;

void Foo(void)
{
   FLS_JobResult_t ProgramStatus;

   /* Then I try to initialize the variable value */
   ProgramStatus = FLS_PROG_SUCCESS;

   ...
}

我接受了一个表明该工具可能存在缺陷的答案。我仍然相信这一点,但我在胡闹试图修复我将 name 添加到 typedef 枚举声明中,现在是:

typedef enum FLS_JobResult_tag
{
   FLS_PROG_SUCCESS,
   FLS_PROG_FAIL,
   FLS_ERASE_SUCCESS2U,
   FLS_ERASE_FAIL,
   FLS_READ_SUCCESS,
   FLS_READ_FAIL,
   FLS_FORMAT_SUCCESS,
   FLS_FORMAT_FAIL
}FLS_JobResult_t;

而且据我所知两者是完全一样的。但是,惊喜! 错误消失了!规则检查器不再将其标记为错误!!

然后做了一些研究我发现了这两个问题:

What are the differences between these two typedef styles in C?

What's the difference between these two enum declarations - C?

我意识到 匿名枚举 命名枚举 之间存在细微差别。但是没有任何内容可以明确规则检查器抱怨另一种形式的原因。

所以问题是:匿名枚举与可能违反 MISRA c 2012 规则 10.3 的命名枚举有什么区别?

对枚举进行类型定义(几乎)总是一个坏主意。

写成这样更好:

enum FLS_JobResult_t
{
   FLS_PROG_SUCCESS,
   FLS_PROG_FAIL,
   FLS_ERASE_SUCCESS2U,
   FLS_ERASE_FAIL,
   FLS_READ_SUCCESS,
   FLS_READ_FAIL,
   FLS_FORMAT_SUCCESS,
   FLS_FORMAT_FAIL
};

void Foo(void)
{
   enum FLS_JobResult_t ProgramStatus;

   /* Then I try to initialize the variable value */
   ProgramStatus = FLS_PROG_SUCCESS;

}

lside (type is anonymous enumeration) = rside (type is anonymous enumeration)左右不知道是相同匿名枚举-因此存在潜在问题。

使用 lside (type is named enumeration) = rside (type is _same_ named enumeration) - 一切正常,已知使用了相同的枚举。

这两个示例都是合规的,并且出于相同的原因:它们不是分配不同基本类型的对象。

让我们来澄清一下。

C 在其类型系统中授予 developers/compilers 很多自由,但它也可能导致意想不到的结果,并可能丢失值、符号或精度。 MISRA-C:2012 通过其 基本类型模型 帮助实施更安全的类型化,这为其规则定义提供了合理的基础,以控制类型转换的使用并提高对实现特定行为的认识( 10.x 规则)。

基本类型模型取代了 MISRA-C:2004 标准的“底层类型”模型(出于某种原因强制执行不必要的强制转换,这导致了很多程序员的悲伤)。

我怀疑您的工具有问题,and/or 部分卡在旧模型上。

与枚举相关的基本类型规则识别两种不同的编程用途:

  1. 枚举类型的对象旨在区别于具有 不同的枚举类型。
  2. 枚举是保存一组整数常量的常用方法。

C 标准没有给出区分这些用途的方法。因此 MISRA-C:2012 添加 以下 不同的基本类型 枚举(同时不影响 C 行为):

  1. 命名枚举类型 - 在此定义的枚举是 由标签或 typedef 标识或用于定义 任何对象、功能或类型;如果整数,则必须使用强制转换 枚举常量的值是必需的。
  2. 匿名枚举类型 - 未在 任何对象、函数或类型的定义。这通常是 用于定义一组常量,这些常量可能相关也可能不相关, 但避免了铸造的需要。

匿名枚举类型的示例:

enum {D = 10, E = 20, F = 30};

您的两个示例都是命名枚举类型(并且它们是兼容的,因为它们是相同的基本类型)。其他例子是:

enum JOHN {A, B, C};
enum PAUL {E, F, G} PAUL;

因此,一个真正的 10.3 违规的例子是:

enum PAUL bar = B;

参考:MISRA-C:2012 附录 D.5“枚举的基本类型”通过其他示例很好地阐述了这一点。

真正的"bug"实际上是在C标准(6.7.2.2)中。 C 保证枚举 constantint 类型,但是枚举 variable 可能是多种不同的类型,例如 char.

至于枚举常量和枚举变量使用哪种基本类型,在MISRA-C:2012附录D.6中有描述。您代码中的枚举常量被认为与命名枚举类型.

具有相同的基本类型

因此该工具不正确,不应发出诊断。