【问题标题】:Why does MISRA-C:2004 throw an error here?为什么 MISRA-C:2004 会在这里抛出错误?
【发布时间】:2015-01-05 11:52:59
【问题描述】:

我似乎不断收到 MISRA-C:2004 规则 10.1 和 10.3 错误,用于以下 sn-p 中的 lShift 分配,并且无法真正看到可以做些什么来满足要求......为什么我仍然出错了?

#define ADC_INTSELxNy_LOG2_NUMBITS_PER_REG 3U
#define ADC_INTSELxNy_NUMBITS_PER_REG 8U
void foo (const bar_e intNumber) {
    uint_least8_t lShift = (uint_least8_t)(ADC_INTSELxNy_NUMBITS_PER_REG - (((((uint_least8_t)intNumber) + 1U) & 0x1U) << ADC_INTSELxNy_LOG2_NUMBITS_PER_REG));
    //...
}

【问题讨论】:

  • 什么是规则 10.1 和 10.3?
  • 10.1:整数类型的表达式的值不应隐式转换为不同的基础类型,如果 A)它不是转换为具有相同符号的更广泛的整数类型,或 B)表达式是复杂的,或者 C) 表达式不是常量并且是函数参数,或者 D) 表达式不是常量并且是返回表达式。
  • 10.3:整数类型的复杂表达式的值只能转换为更窄且与表达式的基础类型具有相同符号的类型。
  • 虽然 10.3 现在似乎已经消失了,尽管我没有改变任何东西......
  • 什么是bar_e?虽然我不清楚“基础类型”在这里应该是什么意思,但 A) 似乎违反了因为uint_least8_t(在大多数系统上)被提升为int。也许将演员表更改为 (unsigned) 并使用 0xff 进行屏蔽(这似乎是您的意图,而不是使用 (unit_least8_t)-1 进行屏蔽)就可以了。不过,我对 MISRA 并不熟悉(并且不同意我目前看到的大多数规则)。

标签: c misra


【解决方案1】:

那一行是一个无法阅读的混乱。考虑将其拆分以增加可读性。 根据系统上 int 的宽度,代码看起来会有所不同。下面的代码假定为 32 位整数。

uint8_t        bit      = (uint8_t)( ((uint32_t)intNumber + 1U) & 0x1U );
uint32_t       lShift32 = ((uint32_t)bit << ADC_INTSELxNy_LOG2_NUMBITS_PER_REG);
uint_least8_t  lShift8  = (uint_least8_t)((uint32_t)ADC_INTSELxNy_NUMBITS_PER_REG - lShift);

现在至于出现错误的原因,规则 10.1 和 10.3 与隐式整数类型提升有关。如果您像我在上面所做的那样拆分代码,您将不会对每个子表达式的“基础类型”感到困惑。您做错的事情是在操作之前 向底层类型添加强制转换,这没有什么好处。您需要在每次操作之后进行

+ 操作需要在 + 操作之后显式转换为基础类型,与 & 操作和 shift 操作相同。最后仅将所有内容都转换为底层类型是不够的,您必须单独考虑每个子表达式。

解释我上面的代码:

第一行显式转换为uint32_t,以确保intNumber1U 的类型相同。这样,子表达式 intNumber + 1U 就没有隐式转换,这是一种与基础类型 uint8_t 相同符号的更广泛类型(意味着它是安全的)。加法的结果是 unsigned int 类型。同样,unsigned int &amp; unsigned int 不会产生隐式转换。最后将结果转换为 uint8_t 以满足许多 MISRA 规则。其余代码以同样的方式进行。

我总是尝试在操作之前将扩展转换为大整数类型,以简化所有内容,避免隐式提升并避免多个转换。

请注意,规则 10.1 的真正目的实际上是强迫您了解 C 中的隐式类型提升。这是一个相当复杂的话题,但数量惊人的 C 程序员却忽略了类型提升以及所有危险和由它们引起的错误。 More info about the type promotion rules here.

【讨论】:

  • 这工作正常,直到我添加最后一步,减法(可能你错过了 + 使用 16 位整数)uint_least8_t lshift8 = (uint_least8_t)(ADC_INTSELxNy_NUMBITS_PER_REG - (uint_least8_t)lShift16);。也许我还没有升职?
  • 啊,应该是uint_least8_t lShift = (uint_least8_t)((uint16_t)ADC_INTSELxNy_NUMBITS_PER_REG - ...。塔
  • @Toby 哎呀,我错过了那部分。让我编辑帖子。实际上,除非 ADC_INTSELxNy_NUMBITS_PER_REG 已经足够大,否则您需要显式转换。
猜你喜欢
  • 2011-09-15
  • 2012-02-26
  • 2013-12-05
  • 1970-01-01
  • 1970-01-01
  • 2012-06-14
  • 2021-06-18
  • 1970-01-01
相关资源
最近更新 更多