指向限定和非限定类型表示的指针
Pointer to qualified and non-qualified type representation
将指向非限定类型的指针重新解释为指向限定类型的指针安全吗?考虑一个包含指针成员"void *ptr"的标准布局类型和另一个定义为"const void *ptr"的标准布局类型。这些类型的布局是否兼容,这个答案是否取决于语言版本或C和c++之间?
动机:
有时在与C程序接口时,定义一个结构体,将参数分组到某种类型的缓冲区。为了const正确性,输入缓冲区应该有指向底层缓冲区的const指针,但输出缓冲区显然必须是可变的。
struct s1 { const void *ptr; }
struct s2 { void *ptr; }
const void *get_in_ptr(void);
void *get_out_ptr(void);
void alg(const s1 *in, const s2 *out);
void f()
{
s1 in_arg = { get_in_ptr() };
s2 out_arg1 = { get_out_ptr() };
s2 out_arg2 = { get_out_ptr() };
/* First algorithm pass. */
alg(&in_arg, &out_arg1);
/* Second algorithm pass. */
alg((const s1 *)&out_arg1, &out_arg2); /* Is this legal? */
}
请在任何答案中引用相关标准出版物
C11 states:
对于任何限定符q,指向非q限定类型的指针都可以转换为指向该类型的q限定版本的指针;存储在原始指针中的值与转换后的指针中的值比较一致。
因此,强制转换为限定版本是安全的,反之则不然。抛出-特别是const
或volatile可以使用不同的内存访问,例如,在哈佛体系结构中将const
变量存储在程序内存(PIC, AVR)中。而且标准对后果也很清楚:
简单地说:一般来说,抛弃这些限定符并不是是安全的。但是,标准没有提到ex-如果试图通过使用非const限定类型的左值来修改用const限定类型定义的对象,则行为未定义。如果试图通过使用非易失性限定类型的左值来引用由易失性限定类型定义的对象,则该行为是未定义的。
const
对象的读访问。
其他限定符和进一步的细节,请阅读自己。
对于结构布局:C使用类型/布局的兼容性,而不是c++。因此,如果两种类型使用相同的布局/标准类型,而不是相同的类型名称,则它们是兼容的。
[C99: 6.2.5/25, C11: 6.2.5/26]:
[.]一个类型的限定或不限定版本是属于同一类型类别的不同类型,具有相同的表示和对齐要求。 [. .]
[C++03, C++11, C++14: 3.9.3/1]:
[…]一个类型的cv-限定或cv-不限定版本是不同的类型;但是,它们应具有相同的表示和对齐要求(3.11)。
对于封装类型:
因此,假设我们忽略了类型系统绕过(
[C99: 6.2.7/1]:
[…]]此外,在单独的翻译单元中声明的两个结构类型、联合类型或枚举类型,如果它们的标签和成员满足以下要求,则它们是兼容的:如果其中一个使用标签声明,则另一个也应使用相同的标签声明。如果两者都是完整类型,则适用以下附加要求:它们的成员之间必须有一对一的对应关系,以便每一对对应的成员都用兼容的类型声明,并且如果对应对中的一个成员用名称声明,则另一个成员也用相同的名称声明。 [. .]
[C++03: 9.2/14]:
如果两个POD-struct (clause 9)类型具有相同数量的非静态数据成员,则它们是布局兼容的,并且相应的非静态数据成员(按顺序)具有布局兼容的类型(3.9)。
[C++11: 9.2/16, C++14: 9.2/17]:
如果两个标准布局结构(第9条)类型具有相同数量的非静态数据成员,并且相应的非静态数据成员(按声明顺序)具有布局兼容类型(3.9),则它们是布局兼容的。
const void*
→void*
到const_cast
,直接或通过c风格强制转换-注意reinterpret_cast
与此无关,并且明确禁止删除cv-限定符),只讨论混叠兼容性…
……是的,这就是"safe"。
这就是为什么我们能够巧妙地使用const_cast
,当古老的C api强迫我们相信他们的话,而不是实际使用const
-safety。
你知道这是可以的,因为当你写&in_arg
时,你的编译器隐式地将s1*
转换为const s1*
进行调用,并且没有抱怨。
- 数组指针表示法C++(移动数组时)
- 使用指针计算堆栈问题的大 O 表示法
- 使用 int 指针的浮点数的位表示形式
- 传递给放置 new 的指针是否是指向其对象表示形式的非 UB 指针?
- C++指针表示法
- char p[0]表示自动分配的缓冲区还是安全指针
- 如何以指针格式表示多维数组?
- 如何将升压数组表示为类型的指针?
- 指针符号在参数规范中表示什么,例如:(char16 *缓冲区,int32 大小)?C++
- ptrdiff_t可以表示指向同一数组对象元素的指针的所有减法吗?
- C 中的动态数组(用指针表示) - 输入元素
- 指针内存表示和继承铸造
- 可以从指向子对象的指针中获取指向完整对象表示元素的指针吗
- 指向对象表示元素或指向提供的存储元素的指针
- 在 C 和指针表示法中放置星号的位置C++
- 指向成员表示的指针
- 为什么使用构造函数调用表示法定义指向指针变量的指针是非法的
- 如何在指针表示法和数组表示法中循环遍历二维数组
- 如何表示指向地址空间开头的指针
- 为什么我们需要不同的数据类型来表示指针