C99 和 MISRA C:2012 中指针转换的未定义行为

问题描述 投票:0回答:1

我正在开发一个 C99 项目,该项目要求我们遵循 MISRA C:2012 标准。

规则 11.3 实质上防止在不同对象类型之间转换指针,而不声明合理的异常批准的偏差(根据 MISRA 合规性)

这背后的原因似乎是为了防止出现未定义的行为

  1. 指针未对齐
  2. 访问“错误”类型的对象(参考C99 6.5第7段)

在我看来,第 2 点只是关于严格的别名规则(至少引用的 C99 段落中的脚注表明了这一点)。

我认为在这个特定项目中两者都不重要,因为......

  1. 底层处理器(Cortex-M7)可以处理未对齐的访问
  2. 基于类型的别名分析和相关的严格别名优化已禁用

我是否遗漏了一些潜在的未定义行为,或者这是违反此规则的有效理由?


编辑:

我同意你的观点,这是代码味道并且破坏了可移植性。此外,我发现根据内存访问的方式和地点,对齐问题仍然是可能的。

但只是添加一些背景信息:我正在处理已经存在的代码,并且对于这种偏差的理由很差。由于涉及到流程开销,因为代码异味而更改它并不是真正的选择。但如果确实存在问题,例如由于未定义的行为,那将是另一回事。如果我可以完全自由地重写代码,我肯定会想以一种不违反此规则的方式来编写它。

c pointers undefined-behavior c99 misra
1个回答
0
投票

不允许此类强制转换的主要原因是错位和“严格别名”,两者都会引发未定义的行为。我们可以看出,除了规则 11.3 之外,还有一条神秘的注释

C11 [未定义 25, 37]

这是一个奇怪的、有点可疑的 MISRA 事情,您应该打开 ISO C11 的附录 J 并计入那里的 UB 汇总列表中。

(这是有问题的,因为附件 J 内容丰富,而且众所周知,它充满了永远得到纠正的错误,许多错误自 C99 以来就一直存在。附件 J 中的很多内容都指出是 UB,然后指向完全不相关的规范部分根本不能证明甚至提及所谓的 UB 是不值得信任的 - 如果出现提示,我可以在其中找出一堆各种错误。)

“未定义 25”是未对齐 UB,“未定义 37”是有效类型/严格别名 UB。

值得注意的是,规则 11.3 对于到字符类型指针的转换(但不是从)到字符类型的指针有一个例外,因为这样既不适用对齐也不适用严格别名。


偏离是否有效?

在嵌入式系统中,存在一些罕见的奇怪情况,可能会引发疯狂的指针转换。例如,Flash/eeprom 驱动程序可能要求您根据传入的字节流编写 C 语言,归结为 16 位或 32 位访问。

偏离规则的另一个有效原因是从结构的第一个成员到指向该结构的指针的对象指针转换,这是由 C 和常见用例明确定义的,但未列为例外在 11.3.

其他情况可能是在 C 中实现诸如

memcpy
或内存池之类的东西时,您需要将双关语从字符类型键入到更大的类型。


底层处理器(Cortex-M7)可以处理未对齐的访问

是的,不是,也许?我不是 ARM 汇编程序专家,但正如评论中所述,M7 仅允许在某些情况下进行未对齐访问,并且我们无法控制从 C 生成哪些汇编指令。因此,如果您打算利用中的指令链接,您需要编写内联汇编程序,在这种情况下,C 语言规则和 MISRA C 超出范围。

基于类型的别名分析和相关的严格别名优化已禁用

您可以禁用的可能别名分析的数量根据编译器的不同而有很大差异。可能很难证明“是的,我确实已经禁用了所有这些”。例如,如果使用 gcc,听起来像是不可能完成的任务。

我是否遗漏了一些潜在的未定义行为,或者这是违反此规则的有效理由?

MISRA C 11.3 将“抛弃限定符”作为 UB 的另一种形式。根据 ISO C17 6.7.3 §7(约束),这将是 UB,并且也包含在 MISRA 11.8 中。
  • 还有一些独立的、健全的 MISRA 规则 11.2 和 11.5 也涵盖了应该考虑的对象指针转换(从不完整类型和到/从 void 指针)。
© www.soinside.com 2019 - 2024. All rights reserved.