我有一个正在使用C99开发的项目,并且正在尝试使其符合MISRA 2012标准。
在一个文件中,我定义了一个枚举,其中每个值都应视为标志:
/**
* Enumerates the configurable options for performing calibration.
*/
typedef enum
{
CALIBRATION_DEFAULT_OPTIONS=0, /**< Calibrate with default options */
CALIBRATION_RESET_POSITION=1, /**< Ensure window is fully open and motor re-homed */
CALIBRATION_FORCE_RECALIBRATE=2 /**< Force recalibration even if calibration data exists */
} CALIBRATION_OPTIONS_T;
我希望能够声明以下内容:
CALIBRATION_OPTIONS_T options = CALIBRATION_RESET_POSITION | CALIBRATION_FORCE_RECALIBRATE;
我还定义了一个接受CALIBRATION_OPTIONS_T
参数并根据设置的标志执行不同逻辑的函数:
// If forced to recalibrate, do so regardless of whether metrics exist in
// EEPROM or not.
if ((options & CALIBRATION_FORCE_RECALIBRATE) != 0U)
{
MOTION_ResetCalibrationData();
calibration = performCalibrationRoutine();
}
// Otherwise try fetching existing metrics from EEPROM. If they exist, return
// these metrics.
else if (tryFetchStoredMetrics(&calibration))
{
if ((options & CALIBRATION_RESET_POSITION) != 0U)
{
calibration.lastPosition = 0;
resetMotorPosition();
storeMetrics(calibration);
}
}
但是,当我用PC-lint Plus擦拭我的项目时,我得到以下输出,说明该代码违反了MISRA 2012规则10.1:
if ((options & CALIBRATION_FORCE_RECALIBRATE) != 0U)
~~~~~~~ ^
*** LINT: src\c\motionCalibrator.c(645) note 9027: an enum value is not an appropriate left operand to & [MISRA 2012 Rule 10.1, required]
if ((options & CALIBRATION_FORCE_RECALIBRATE) != 0U)
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*** LINT: src\c\motionCalibrator.c(645) note 9027: an enum value is not an appropriate right operand to & [MISRA 2012 Rule 10.1, required]
if ((options & CALIBRATION_FORCE_RECALIBRATE) != 0U)
^
*** LINT: src\c\motionCalibrator.c(645) warning 641: implicit conversion of enum 'CALIBRATION_OPTIONS_T' to integral type 'unsigned int'
if ((options & CALIBRATION_RESET_POSITION) != 0U)
~~~~~~~ ^
*** LINT: src\c\motionCalibrator.c(655) note 9027: an enum value is not an appropriate left operand to & [MISRA 2012 Rule 10.1, required]
if ((options & CALIBRATION_RESET_POSITION) != 0U)
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~
*** LINT: src\c\motionCalibrator.c(655) note 9027: an enum value is not an appropriate right operand to & [MISRA 2012 Rule 10.1, required]
if ((options & CALIBRATION_RESET_POSITION) != 0U)
^
*** LINT: src\c\motionCalibrator.c(655) warning 641: implicit conversion of enum 'CALIBRATION_OPTIONS_T' to integral type 'unsigned int'
尤其是,出于以下两个原因,MISRA 2012标准建议不要将枚举&
与枚举一起使用:
本质上为枚举类型的操作数不应在 算术运算,因为枚举对象使用 实现定义的整数类型。涉及枚举的操作 因此,对象可能会产生意外类型的结果。注意 来自匿名枚举的枚举常量已基本签名 类型。
仅应对以下操作数执行移位和按位运算 本质上是无符号的类型。由其使用产生的数值 基本上是签名类型上的是实现定义的。
我想知道是否有一种符合MISRA的方式,我可以使用类似标志的枚举并测试是否设置了特定标志。
答案 0 :(得分:5)
这归结为基本类型模型和规则10.1。仅允许您对本质上无符号的类型执行按位运算。 MISRA-C将枚举视为自己的唯一类型。
使用CALIBRATION_OPTIONS_T options = CALIBRATION_RESET_POSITION | CALIBRATION_FORCE_RECALIBRATE;
之类的方法可以很好地完成C语言的规范工作,但是您必须求助于使用无符号常量。为了将类型安全性发挥到极致,您可以这样做:
typedef uint32_t CALIBRATION_OPTIONS_T;
#define CALIBRATION_DEFAULT_OPTIONS ((CALIBRATION_OPTIONS_T)0x00u) /**< Calibrate with default options */
#define CALIBRATION_RESET_POSITION ((CALIBRATION_OPTIONS_T)0x01u) /**< Ensure window is fully open and motor re-homed */
#define CALIBRATION_FORCE_RECALIBRATE ((CALIBRATION_OPTIONS_T)0x02u) /**< Force recalibration even if calibration data exists */
十六进制表示法是表明这些是位掩码的自说明代码,在某些情况下MISRA需要使用u
后缀,并且在其中uint32_t
可以阻止潜在的隐式类型提升。 / p>
请注意,使用枚举不一定会提高类型安全性,反之则相反。在许多情况下,它们被视为纯int
,在其他情况下,它们被视为实现定义的大小整数。 C语言设计几乎破坏了它们的类型安全性。尽管您可以通过一些技巧使它们安全,但是请访问How to create type safe enums?上的我的帖子。