分配给更广泛的基本类型的表达式

Expression assigned to a wider essential type

我从我们的分析工具中收到以下警告 Composite expression assigned to a wider essential type 这是代码:

uint32_t result;
uint8_t resolution;

result = 1U << resolution;

我尝试了以下方法:

#define SHIFT_BY_ONE (uint8_t)1
result  = SHIFT_BY_ONE << resolution;

但那会引发此警告 Shift left of signed quantity (int) 所以我想我没有正确理解这个问题。我该如何解决这个错误?

在您的系统上 1U 可能是 16 位无符号的(这解释了在尝试分配给 32 位无符号时的 "wider type")。

在那种情况下,我会使用 long 后缀作为文字:

result = 1UL << resolution;

(一些评论建议 ((uint32_t)1U) << resolution 这毕竟是最便携的方式)

发生这种情况是因为 1Uuint32_t 类型不匹配。使用 确保类型兼容性:

result = UINT32_C(1) << resolution;

这听起来好像您是 运行 MISRA-C:2012 检查员。 基本类型复合表达式是MISRA-C中的术语,而不是C标准中的术语。

为了从这个警告中理解任何东西,你必须研究基本类型 (MISRA-C:2012 8.10) 和复合表达式 (MISRA-C:2012 8.10.3) 的含义。

至于警告的原因,是规则10.6:

The value of a composite expression shall not be assigned to an object with wider essential type.

如果我们忽略所有这些术语的含义,则规则归结为如果您有一个具有 2 个较小类型的操作数的运算,则结果不应分配给比那些更大类型的变量操作数。

这是为了防止这样的代码:

uint16_t a = 40000;
uint16_t b = 40000;
uint32_t result = a + b;

在 16 位系统上,操作数 ab 不会被提升,因此实际操作将在 16 位类型上执行 - 并且会有一个无符号换行 -周围(或在有符号变量的情况下溢出)。

不理解隐式类型提升在 C 中是如何工作的困惑的程序员可能认为上述操作在 uint32_t 上执行只是因为结果存储在这样的类型中。但这是不正确的,赋值运算符的左侧与子表达式 a + b 无关。子表达式中使用哪种类型完全由运算符优先级决定,= 的优先级低于 +.

显然 MISRA-C 认为这种误解很普遍,这就是这条规则的基本原理。

至于怎么解决,很简单:

result = (uint32_t)1U << resolution;

1U 可能比 uint32_t 更窄(16 位),因此 "Composite expression assigned to a wider essential type"。将 16 位 unsigned 移位 20 不会得到 0x100000,

uint32_t result;
uint8_t resolution;
result = 1U << resolution; // Potential 16-bit assignment to a 32-bit type.

resolution 的狭窄在这里不是问题。


How do I fix this error?

我更愿意在可能的情况下避免转换并提供 2 个替代方案。两者都首先有效地创建目标类型的 1 而无需强制转换。编译器肯定会发出优化代码。

result = 1u;
result <<= resolution;
// or 
result = (result*0u + 1u) << resolution;