在 core_cm4.h 上,为什么会有类似 ((uint32_t)(int32_t)IRQn) 的转换?
On core_cm4.h why is there casting like ((uint32_t)(int32_t)IRQn)?
在来自 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));
}
这样做的目的是什么?
由于 CM4 软件为核心实现了负中断源,您必须先将值转换为 32 位有符号整数,然后再转换为无符号 32 位,以便在数字左侧填充零进行适当的右移。
CM4 使用 -15 到 -1 作为 CM4-Core 源,从 0 到下一个作为供应商特定源。
假设IRQn
是你说的范围内的一个整数(任何有符号整数类型),那么(uint32_t)(int32_t)IRQn
和(uint32_t)IRQn
.
是完全一样的
代码作者可能没有理解C类型转换规则;这是基于价值观,而不是陈述。例如,将 -3
转换为 uint32_t
总是得到 UINT32_MAX - 2
,而不管 -3
是哪种数据类型。重要的是 "negative 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 要求移位表达式的结果应立即转换为 "underlying type"(MISRA 术语)。因此,也可以编写 (IRQn_Type)(IRQn >> 5UL)
,它仍然符合 MISRA-C:2004。
但是,MISRA 中没有任何内容阻止您在转换之前将自己的转换添加到不同的类型,例如 uint32_t
。这是一个更好的做法,因为它完全消除了隐式提升。
对于那些对 C 中的隐式类型提升如何工作感到困惑的人,请参阅 。
在来自 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));
}
这样做的目的是什么?
由于 CM4 软件为核心实现了负中断源,您必须先将值转换为 32 位有符号整数,然后再转换为无符号 32 位,以便在数字左侧填充零进行适当的右移。
CM4 使用 -15 到 -1 作为 CM4-Core 源,从 0 到下一个作为供应商特定源。
假设IRQn
是你说的范围内的一个整数(任何有符号整数类型),那么(uint32_t)(int32_t)IRQn
和(uint32_t)IRQn
.
代码作者可能没有理解C类型转换规则;这是基于价值观,而不是陈述。例如,将 -3
转换为 uint32_t
总是得到 UINT32_MAX - 2
,而不管 -3
是哪种数据类型。重要的是 "negative 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 要求移位表达式的结果应立即转换为 "underlying type"(MISRA 术语)。因此,也可以编写 (IRQn_Type)(IRQn >> 5UL)
,它仍然符合 MISRA-C:2004。
但是,MISRA 中没有任何内容阻止您在转换之前将自己的转换添加到不同的类型,例如 uint32_t
。这是一个更好的做法,因为它完全消除了隐式提升。
对于那些对 C 中的隐式类型提升如何工作感到困惑的人,请参阅