【问题标题】:Implicit Pointer-To-Const-T conversion隐式 Pointer-To-Const-T 转换
【发布时间】:2018-04-03 14:53:46
【问题描述】:

我想知道是否隐式转换为指向 const 数据类型的指针是在 C11 标准中定义的:

T x;
const T *p = &x;

指向T 类型对象的指针被隐式转换为指向const T 类型对象的指针。这种隐式转换是否在 C11 标准中定义? (我知道允许这样做是有意义的以及它有多么有用。我只是想知道它在标准中的定义)

此外,根据 C11 是否禁止从类型 T**const T** 的隐式转换?

T *p;
const T **pp = &p;

这是一个众所周知的问题部分,因此 GCC 和 LLVM/clang 会发出警告。我仍然想知道根据 C11 标准是否允许这样做。我只在 §6.5.16.1P6 中找到一条评论,指出这应该是违反约束。但是,我看不出应该违反哪个约束。我再次知道这应该被禁止,并且这种隐式转换可能会导致微妙的问题。我只是想知道这是否是根据 C11 定义的(未)行为。

再一次,我的两个问题不是关于这是否好(这里已多次回答),而是 C11 标准如何/在何处定义这一点。


为了完整起见,这里是第二个示例有问题的原因的链接:http://c-faq.com/ansi/constmismatch.html

【问题讨论】:

  • 第 6.3.2.3 节第 2 段。

标签: c constants language-lawyer


【解决方案1】:

指向 T 类型对象的指针被隐式转换为 指向 const-T 类型对象的指针。这是隐式转换吗 在 C11 标准中定义的某个地方?

是的。这种隐式转换是标准强制要求的。

6.5.4 Cast Operators 部分的Paragraph 3 这么说

涉及指针的转换,除 6.5.16.1 的约束,应通过显式的方式指定 演员表。

第 3 点下引用的 6.5.16.1 说:

左操作数具有原子、限定或非限定指针类型, 和(考虑到左操作数在左值之后的类型 转换)两个操作数都是指向合格或不合格的指针 兼容类型的版本,左边指向的类型有 右边指向的类型的所有限定符;

因此,const T *p = &x; 的隐式转换成立,因为您只是添加限定符,而不是删除它们。

const T **pp = &p; 不属于此范围,因此您需要显式强制转换(C++ 将允许 const T*const*pp = &p;(需要第二个 const),但 C 仍然不允许。)

只要对齐匹配(对于指向不同限定类型的指针,它们会匹配),就 UB 而言,通过显式强制转换的指针转换不是问题,因为 6.3.2.3p7 保证:

指向对象类型的指针可以转换为指向对象类型的指针 不同的对象类型。如果结果指针不正确 aligned68) 对于引用的类型,行为未定义。 否则,当再次转换回来时,结果将比较相等 到原来的指针。当指向对象的指针转换为 指向字符类型的指针,结果指向最低地址 对象的字节。结果的连续递增,直到 对象的大小,产生指向剩余字节的指针 对象。

但您需要注意将由strict aliasing rule 管理的访问/取消引用:

对象的存储值只能由左值访问 具有以下类型之一的表达式:88)

与对象的有效类型兼容的类型,合格的 与对象的有效类型兼容的类型的版本,a type 是有符号或无符号类型,对应于 对象的有效类型,有符号或无符号的类型 type 对应于有效类型的限定版本 对象,聚合或联合类型,包括以下之一 其成员之间的上述类型(包括,递归地, 子聚合或包含联合的成员)或字符类型。

【讨论】:

  • 我的第一个想法也是第 6.5.16.1 段第 3 段应该成立(至少对于第一种情况)。但是,我的想法被以下措辞扭曲了:“两个操作数都是指向兼容类型的合格或不合格版本的指针”。这是否意味着const TT 是兼容类型?根据我的理解,它们不是,第 6.7.3 节第 10 段说“对于两个兼容的合格类型,两者都应具有兼容类型的相同合格版本”。虽然这并不真正适合,因为不是两种类型都符合条件。
  • 很抱歉第二次回复,但我的字符用完了;)你能详细说明为什么第二种情况不属于 §6.5.16.1 吗?我的意思是,如果const TT 兼容,那么const T*T* 应该是兼容的,因此§6.5.16.1 也应该适用于const T**T**。还是我错过了一些东西(不过,我可能应该休息一下,然后睡一觉)。
  • @MaxMaier 类型兼容性似乎是一个非常复杂的定义概念,其定义遍布整个标准(请参阅我在stackoverflow.com/questions/49479461/… 上的问题),但基本上(据我所知)在上下文中兼容of types 表示相同且相同限定,但需要注意可能存在不完整的部分:intint const 不兼容,但 int[] /*incomplete*/int[42] 兼容(当然,这不是传递性的)。跨度>
  • 嗯,最后一个例子是一个简洁的例子。感谢您澄清这一点!
猜你喜欢
  • 2011-10-21
  • 2020-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-11
  • 2011-01-01
相关资源
最近更新 更多