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-std :: visit for variant无法在clang 5下编译


下一篇:保留C类型信息以归档以在程序调用中使用