MISRA-C:2012 规则 10.8 警告 "being cast to a wider type"
MISRA-C:2012 warning of Rule 10.8 "being cast to a wider type"
我收到规则 10.8 的 MISRA-C 警告:
'essentially unsigned' 类型(unsigned char)的复合表达式正在转换为更宽的无符号类型,'unsigned short'.
此警告是使用以下代码检测到的。
void Fucntion(unsigned char isSwitchOn) {
unsigned short switchMask = 0U;
switchMask |= (unsigned short)(isSwitchOn & 1U) << 1;
为什么检测到警告?
另外,这段代码会导致问题吗?
我认为是将表达式(isSwitchOn & 1U)转为int类型计算,结果截断为unsigned short类型存储。这么想,警告对我来说似乎不自然。
关于:
unsigned short switchMask = 0U;
此语句正在使用 unsigned int
分配 unsigned short int
关于:
switchMask |= (unsigned short)(isSwitchOn & 1U) << 1;
此语句正在将 unsigned short int
与 unsigned int
相结合
Why was a warning detected?
让我们看看
void Fucntion(unsigned char isSwitchOn) {
unsigned short switchMask = 0U;
switchMask |= (unsigned short)(isSwitchOn & 1U) << 1;
isSwitchOn
,排名低于 1U
,经过 通常的算术转换 (C11 §6.5.10 3)到类型 unsigned
以匹配 1U
.
的类型
计算isSwitchOn & 1U
,结果类型为unsigned
.
Cast (unsigned short)
应用于 unsigned
结果 - 这一步看起来很奇怪。 这是规则 10.8 的 MISRA-C 警告。不需要演员表。 复合类型 unsigned
不必要地缩小为 unsigned short
。
(unsigned short)
结果准备移位,整数提升 对 <<
的每个操作数执行。因此 (unsigned short)
被提升为 int
或者可能 unsigned
如果 USHRT_MAX > INT_MAX
。让我们假设 int
.
现在发生 int
的移位。结果类型为 int
.
int
应用于unsigned short
。
Also, does this code cause problems?
我没有看到 在这个 案例中,导致问题的转换不是 WET 编程。如果结果是 unsigned switchMask
,是的,那么移出的位就会丢失。
在移位后转换结果更有意义。
switchMask |= (unsigned short)((isSwitchOn & 1U) << 1);
或使用
避免其他潜在警告
switchMask = (unsigned short)(switchMask | ((isSwitchOn & 1U) << 1));
I think that the expression (isSwitchOn & 1U)
is converted to an int type and calculated
不是,表达式(unsigned short)(isSwitchOn & 1U)
转换成int类型计算
注意:unsigned char isSwitchOn
和unsigned short switchMask
不是同一种类型是可疑的
Chux 发布了一个答案,解释了代码发生了什么以及错误的原因。至于怎么修,那就得重写了。有两个问题:
- 您正在使用一个字符类型作为布尔值,然后您还在算术中使用该字符类型,在提升之后而不是在提升之前转换类型。据说这样做是为了摆脱多余的分支。
- 您正在使用 C 的本机整数类型,它可以具有任何大小。这不是推荐的做法,并且违反了 MISRA-C:2012 Dir 4.6。摆脱这些类型并改用
stdint.h
,这样您就可以编写确定性的、可移植的代码。
现在有两种方法可以处理隐式类型提升:要么让它们发生,然后再强制转换——这通常是 MISRA 更喜欢的方式。或者您根本不让它们发生,方法是在评估操作之前强制转换为宽无符号类型,从而消除隐式提升。就 MISRA 而言,两者都应该没问题;我个人更喜欢后者。
固定代码如下所示:
// ok if 8/16 bit system only
void Function (bool isSwitchOn) {
uint16_t switchMask = ((uint16_t)isSwitchOn & 1U) << 1U;
或
// 32 bit system/fully portable code
void Function (bool isSwitchOn) {
uint32_t shift = (uint32_t)isSwitchOn & 1U;
uint16_t switchMask = (uint16_t) (shift << 1U);
请注意,这些示例应生成完全相同的机器代码。所以您也可以在 8 位系统上使用完全便携的版本。两者在给定系统上均符合 MISRA-C - 任何地方都不会发生隐式提升。
更多信息:。
我收到规则 10.8 的 MISRA-C 警告: 'essentially unsigned' 类型(unsigned char)的复合表达式正在转换为更宽的无符号类型,'unsigned short'.
此警告是使用以下代码检测到的。
void Fucntion(unsigned char isSwitchOn) {
unsigned short switchMask = 0U;
switchMask |= (unsigned short)(isSwitchOn & 1U) << 1;
为什么检测到警告? 另外,这段代码会导致问题吗?
我认为是将表达式(isSwitchOn & 1U)转为int类型计算,结果截断为unsigned short类型存储。这么想,警告对我来说似乎不自然。
关于:
unsigned short switchMask = 0U;
此语句正在使用 unsigned int
unsigned short int
关于:
switchMask |= (unsigned short)(isSwitchOn & 1U) << 1;
此语句正在将 unsigned short int
与 unsigned int
Why was a warning detected?
让我们看看
void Fucntion(unsigned char isSwitchOn) {
unsigned short switchMask = 0U;
switchMask |= (unsigned short)(isSwitchOn & 1U) << 1;
isSwitchOn
,排名低于1U
,经过 通常的算术转换 (C11 §6.5.10 3)到类型unsigned
以匹配1U
. 的类型
计算isSwitchOn & 1U
,结果类型为unsigned
.Cast
(unsigned short)
应用于unsigned
结果 - 这一步看起来很奇怪。 这是规则 10.8 的 MISRA-C 警告。不需要演员表。 复合类型unsigned
不必要地缩小为unsigned short
。(unsigned short)
结果准备移位,整数提升 对<<
的每个操作数执行。因此(unsigned short)
被提升为int
或者可能unsigned
如果USHRT_MAX > INT_MAX
。让我们假设int
.现在发生
int
的移位。结果类型为int
.int
应用于unsigned short
。
Also, does this code cause problems?
我没有看到 在这个 案例中,导致问题的转换不是 WET 编程。如果结果是 unsigned switchMask
,是的,那么移出的位就会丢失。
在移位后转换结果更有意义。
switchMask |= (unsigned short)((isSwitchOn & 1U) << 1);
或使用
避免其他潜在警告switchMask = (unsigned short)(switchMask | ((isSwitchOn & 1U) << 1));
I think that the expression
(isSwitchOn & 1U)
is converted to an int type and calculated
不是,表达式(unsigned short)(isSwitchOn & 1U)
转换成int类型计算
注意:unsigned char isSwitchOn
和unsigned short switchMask
不是同一种类型是可疑的
Chux 发布了一个答案,解释了代码发生了什么以及错误的原因。至于怎么修,那就得重写了。有两个问题:
- 您正在使用一个字符类型作为布尔值,然后您还在算术中使用该字符类型,在提升之后而不是在提升之前转换类型。据说这样做是为了摆脱多余的分支。
- 您正在使用 C 的本机整数类型,它可以具有任何大小。这不是推荐的做法,并且违反了 MISRA-C:2012 Dir 4.6。摆脱这些类型并改用
stdint.h
,这样您就可以编写确定性的、可移植的代码。
现在有两种方法可以处理隐式类型提升:要么让它们发生,然后再强制转换——这通常是 MISRA 更喜欢的方式。或者您根本不让它们发生,方法是在评估操作之前强制转换为宽无符号类型,从而消除隐式提升。就 MISRA 而言,两者都应该没问题;我个人更喜欢后者。
固定代码如下所示:
// ok if 8/16 bit system only
void Function (bool isSwitchOn) {
uint16_t switchMask = ((uint16_t)isSwitchOn & 1U) << 1U;
或
// 32 bit system/fully portable code
void Function (bool isSwitchOn) {
uint32_t shift = (uint32_t)isSwitchOn & 1U;
uint16_t switchMask = (uint16_t) (shift << 1U);
请注意,这些示例应生成完全相同的机器代码。所以您也可以在 8 位系统上使用完全便携的版本。两者在给定系统上均符合 MISRA-C - 任何地方都不会发生隐式提升。
更多信息: