为什么匿名枚举不符合 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 部分卡在旧模型上。
与枚举相关的基本类型规则识别两种不同的编程用途:
- 枚举类型的对象旨在区别于具有
不同的枚举类型。
- 枚举是保存一组整数常量的常用方法。
C 标准没有给出区分这些用途的方法。因此 MISRA-C:2012 添加 以下 不同的基本类型 枚举(同时不影响 C 行为):
- 命名枚举类型 - 在此定义的枚举是
由标签或 typedef 标识或用于定义
任何对象、功能或类型;如果整数,则必须使用强制转换
枚举常量的值是必需的。
- 匿名枚举类型 - 未在
任何对象、函数或类型的定义。这通常是
用于定义一组常量,这些常量可能相关也可能不相关,
但避免了铸造的需要。
匿名枚举类型的示例:
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 保证枚举 constant 是 int
类型,但是枚举 variable 可能是多种不同的类型,例如 char
.
至于枚举常量和枚举变量使用哪种基本类型,在MISRA-C:2012附录D.6中有描述。您代码中的枚举常量被认为与命名枚举类型.
具有相同的基本类型
因此该工具不正确,不应发出诊断。
有问题:
我在使用此代码时遇到问题,因为未通过 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 部分卡在旧模型上。
与枚举相关的基本类型规则识别两种不同的编程用途:
- 枚举类型的对象旨在区别于具有 不同的枚举类型。
- 枚举是保存一组整数常量的常用方法。
C 标准没有给出区分这些用途的方法。因此 MISRA-C:2012 添加 以下 不同的基本类型 枚举(同时不影响 C 行为):
- 命名枚举类型 - 在此定义的枚举是 由标签或 typedef 标识或用于定义 任何对象、功能或类型;如果整数,则必须使用强制转换 枚举常量的值是必需的。
- 匿名枚举类型 - 未在 任何对象、函数或类型的定义。这通常是 用于定义一组常量,这些常量可能相关也可能不相关, 但避免了铸造的需要。
匿名枚举类型的示例:
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 保证枚举 constant 是 int
类型,但是枚举 variable 可能是多种不同的类型,例如 char
.
至于枚举常量和枚举变量使用哪种基本类型,在MISRA-C:2012附录D.6中有描述。您代码中的枚举常量被认为与命名枚举类型.
具有相同的基本类型因此该工具不正确,不应发出诊断。