c – 使用std :: launder从指向非活动对象的指针获取指向活动对象成员的指针?
作者:互联网
这个问题跟随这个one
我们来考虑这个示例代码:
struct sso
{
union{
struct {
char* ptr;
char size_r[8];
} large_str;
char short_str[16];
};
bool is_short_str() const{
return *std::launder(short_str+15)=='\0'; //UB?
}
};
如果short_str不是取消引用指针而没有std :: launder的活动成员则是UB.让我们考虑ABI已经明确指定,并且我们知道size_r [7]与short_str [15]位于同一地址.当short_str不是联合的活动成员时,std :: launder(short_str 15)是否返回指向size_r [7]的指针?
Nota:我认为这是因为[ptr.launder]/3
A byte of storage is reachable through a pointer value that points to an object Y if it is within the storage occupied by Y, an object that is pointer-interconvertible with Y, or the immediately-enclosing array object if Y is an array element.
解决方法:
Let’s consider that the ABI is well specified and that we know that size_r[7] is at the same address as short_str[15]
这完全取决于保证的确切含义.
编译器可以自由地保证
Sso.short_str[15]
即使Sso.large_str当前处于活动状态,也可以访问和修改所有内容,并获得您期望的语义.
或者免费提供保证.
对于形成不良或表现出未定义行为的行为或程序没有任何限制.
由于那里没有对象,& Sso.short_str [15]与任何东西都不是指针可互换的.不存在的对象没有与另一个对象“相同的地址”.
Launder是根据指向预先存在的对象的指针定义的.然后销毁该指针,并创建具有相同地址的新对象(定义明确).然后std :: launder允许您将指针指向不再存在的对象,并获取指向现有对象的指针.
你在做什么不是那个.如果你使用了& short_str [15],你就会得到一个指向对象的指针. ABI可以说这与size_r处于同一地址[7].现在std :: launder将处于有效性范围内.
但编译器可以更进一步,定义short_str [15]引用与size_r [7]相同的对象,即使它不活动.
最弱的ABI保证我能看到与你的东西保持一致只有你在活动时使用short_str [15]的地址才能起作用;之后,您将使用large_str,然后您可以从& short_str [15]清洗到& size_r [7].与您的陈述一致的最强ABI保证使得不需要调用std :: launder.在std :: washder中间的某个地方是必需的.
标签:c,language-lawyer,pointers,unions,c17 来源: https://codeday.me/bug/20191007/1869414.html