首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MISRA C:2004,位移位错误

MISRA C:2004,位移位错误
EN

Stack Overflow用户
提问于 2012-02-04 01:47:13
回答 3查看 4.3K关注 0票数 4

我正在使用带有MISRA :2004的编译器。

碎片是:

代码语言:javascript
复制
#define UNS_32 unsigned int
UNS_32 arg = 3U;
UNS_32 converted_arg = (UNS_32) arg;
/* Error line --> */ UNS_32 irq_source = (UNS_32)(1U << converted_arg);

MISRA错误是: ErrorPm136:从底层MISRA类型"unsigned“到"unsigned”的非法显式转换(MISRA 2004规则10.3)

我在上面的代码中没有看到任何unsigned char

Why did Misra throw an error here?的讨论讨论了乘法,它可能有不同的促进规则,而不是左移。

我的理解是,编译器应该将表达式提升到较大的数据类型,而不是降级到更小的大小。

这到底是怎么回事?

如何使代码MISRA C:2004兼容?

编辑1:

将错误行更改为:

代码语言:javascript
复制
UNS_32 irq_source = (UNS_32)((UNS_32) 1U << converted_arg);  

不是让错误消失了吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-02-06 10:24:10

第二个问题:

如何使代码MISRA :2004兼容?

您可以以符合MISRA的方式编写它,如下所示:

代码语言:javascript
复制
typedef unsigned int UNS_32;

UNS_32 test(void);
UNS_32 test(void)
{
  UNS_32 original_arg = 3U;
  UNS_32 irq_source = 1UL << original_arg;

  return irq_source;
}

回到第一个问题:

这里到底发生了什么?

第一条规则10.3规定,复杂整数表达式不应转换为比基础类型更宽的类型。

理解错误消息的一个关键是基本类型的概念,这是一个特定于MISRA-C的概念。简而言之,常数的底层类型是它可以容纳的最小类型。在本例中,1U具有底层类型unsigned char,尽管它具有语言类型unsigned int

10.3规则的基本原理是避免在比部分更大的上下文中使用操作的结果。这方面的标准示例是乘法,其中alphabeta是16位类型:

代码语言:javascript
复制
uint32_t res = alpha * beta;

这里,如果int是16位,则乘法将以16位执行,然后将结果转换为32位。另一方面,如果int为32位或更大,则将以更高的精度执行乘法。具体而言,这将使结果在乘以0x4000和0x10时有所不同。

MISRA规则10.3解决了这一问题,强制将强制结果放置在一个临时的位置,然后将其转换为更大的类型。这样,您就不得不以某种方式编写代码。

如果目的是使用16位乘法:

代码语言:javascript
复制
uint16_t tmp = alpha * beta;
uint32_t res = tmp;

另一方面,如果目的是32位乘法:

代码语言:javascript
复制
UNS_32 res = (UNS_32)alpha * (UNS_32)beta;

因此,在这种情况下,表达式1U << count是潜在的问题。如果converted_arg大于16位,这可能会导致使用16位ints. MISRA允许您编写1UL << count(UNS_32)((UNS_32)1U << original_arg)时出现问题。你提到米斯拉检查器在后一种情况下发出了一个错误-请再次检查。

所以,在我看来,你使用的MISRA C检查器正确地识别了违反规则10.3的行为。

票数 4
EN

Stack Overflow用户

发布于 2012-02-04 04:29:22

在米斯拉规则指定的C89中,以U后缀的整数常量的类型是列表“无符号int,无符号长int”中的第一个,其中可以表示其值。这意味着1U的类型必须是unsigned int

按位移位运算符的定义指定对每个操作数执行整数提升(这不会改变unsigned int),并且结果的类型是提升的左操作数的类型。因此,在这种情况下,(1U << converted_arg)的结果类型是unsigned int

这里唯一的显式转换是将此unsigned int值转换为unsigned int,所以这必须是编译器所警告的--尽管看不到unsigned char,这意味着检查器似乎是错误的。

但从技术上讲,从unsigned intunsigned int的转换似乎违反了规则10.3,该规则规定,“复杂表达式”的结果只能转换为较窄的类型,而转换到相同类型的结果显然不能转换为较窄的类型。

演员阵容是没有必要的--我只想省略一下。

票数 3
EN

Stack Overflow用户

发布于 2018-10-18 20:25:31

在MISRA的早期,应用它的程序有时会针对那些行为不符合尚未发布的C89标准的编译器。在发明C的机器上,对16位值的操作与对8位值的操作所花费的费用相同。将char值提升到int,并在存储回char时截断结果实际上比直接对char值执行算术更便宜和容易。C标准一旦发布,就会要求所有C实现必须将所有整数值提升为至少可以容纳范围-32767.32767的int类型,或者至少可以容纳0..65535的unsigned类型,或者更大的类型,以8位计算机为目标的1980年代编译器并不总是这样做的。

虽然现在尝试使用不能满足这些要求的C编译器似乎很疯狂,但是80年代的程序员通常会面临着在使用"C-ish“编译器还是用汇编语言编写所有东西之间的选择。MISRA中的一些规则,包括“固有类型”规则,旨在确保程序即使在将int视为8位类型的奇怪实现上运行也是有效的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9137737

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档