在core_cm4.h上为什么会像((uint32_t)(int32_t)IRQn那样)?

时间:2017-03-29 13:40:35

标签: c arm cortex-m3 cortex-m cmsis

在core_cm4.h的以下代码中,为什么会有双重演员((uint32_t)(int32_t)IRQn)

例如,在以下函数中:

__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{
  NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}

这是为了什么目的?

3 个答案:

答案 0 :(得分:4)

由于CM4软件为核心实现负中断源,因此必须先将值转换为32位有符号整数,然后再转换为无符号32位,以便在数字左侧使用填充零进行正确的右移。

CM4使用-15到-1作为CM4核心源,从0到下一个作为供应商特定来源。

答案 1 :(得分:3)

通过查看该片段,很明显无论是谁编写它都会对隐式类型推广规则的工作方式感到困惑。另外,>> 5UL看起来非常可疑,当我看到我立即怀疑这个代码库对MISRA-C的理解不足时;可能他们正在使用一台坏的静态分析仪,它会吐出误报。

对Github的访问证明了我的怀疑是正确的,有评论表明其目的是遵循MISRA-C:2004。

MISRA-C要求不得进行危险的隐式促销活动。演员阵容是一些失败的尝试沉默静态分析器,但没有理解为什么工具给出了这些警告。

正确,MISRA-C(2004和2012)兼容代码将是:

NVIC->ISER[((uint32_t)IRQn>>5UL)] = (1UL << ((uint32_t)IRQn & 0x1FUL));

(MISRA-C要求复杂的子表达式必须使用括号,尽管运算符具有优先级。)

这段代码仍然很混乱,因此最好将其重写为可读性,以便生成完全相同的机器代码:

uint32_t ISER_index = ((uint32_t)IRQn >> 5UL);
uint32_t shift_n    = ((uint32_t)IRQn & 0x1FUL);
NVIC->ISER[ISER_index] = (1UL << shift_n);

旁注:
MISRA-C:2004要求将班次表达的结果立即转换为“基础类型”(MISRA术语)。因此,人们也可以写(IRQn_Type)(IRQn >> 5UL),它仍然符合MISRA-C:2004标准。

但是,MISRA中没有任何内容阻止您在轮班之前将自己的演员阵容添加到其他类型,例如uint32_t。这是一件更好的事情,因为它完全消除了隐含的促销。

对于那些对C中隐式类型促销如何工作感到困惑的人,请参阅Implicit type promotion rules

答案 2 :(得分:2)

假设IRQn是您所说范围内的整数(任何有符号整数类型),则(uint32_t)(int32_t)IRQn(uint32_t)IRQn完全相同。

代码的作者可能不了解C类型转换规则;它们基于价值而非表示。无论-3是哪种数据类型,将uint32_t转换为UINT32_MAX - 2总是会-3。这是&#34;负3&#34;的价值。这很重要。

(另一个答案解释了使用强制转换和不使用强制转换之间的区别。)