【问题标题】:Does the strict-aliasing rules apply across function calls?严格别名规则是否适用于函数调用?
【发布时间】:2019-09-05 11:58:33
【问题描述】:

关于下面的示例,在f1 中,没有出现别名,因为p(void*) 不可访问,而p1 是唯一访问内存的指针。 但是,p1(float*) 和 p2(int*) 之间存在指针别名,位于 f1 之外。
我的问题是,这个别名是否非法,也就是说,严格别名规则是否适用于函数调用?

如果这个例子是有效的,如果 f1 是内联的呢?

void f1(void *p)
{
  auto* p1 = static_cast<float*>(p);
  *p1 = 1.f;
}

int f2()
{
  int x = 1;
  auto* p2 = &x;
  f1(&x);
  *p2 = 1;
  return *p2;
}

【问题讨论】:

  • "如果 f1 被内联怎么办" - 内联对严格的别名规则 AFAIK 没有任何影响。无论编译器是否选择内联,代码都需要在别名方面始终正确。
  • 这是否违反了严格的别名;另一个考虑:这是否违反对象生命周期?分配对象时,*p1 处是否存在 float 类型的对象?
  • memcpy 具有特殊权限并已被优化掉,因此请使用它而不是 static_cast 来获得优势。
  • @eerorika 我假设一个对象是通过赋值创建的(应该如此),该对象与曾经驻留在此处的任何其他不兼容对象类型无关。其他指针会失效吗?
  • @curiousguy 你能假设一个对象是通过赋值创建的吗? This post 不同意。 对象由定义([basic.def])、新表达式([expr.new])、隐式更改联合的活动成员([class.union])或当创建了一个临时对象([conv.rval], [class.temporary])。

标签: c++ language-lawyer strict-aliasing


【解决方案1】:

无论您复制指针多少次或将其传递到其他位置或转换它多少次,决定因素始终是实际存储在该位置的内容。

在您的情况下,唯一重要的是static_cast 的参数是否实际上是float 的地址,而事实并非如此。

【讨论】:

  • 更准确地说,唯一重要的是*p1 是否实际上引用了float 类型的对象。它没有,因此是UB。这只是为了澄清问题不在于static_cast 本身,而是通过the wrong type 的左值访问对象的存储值...
  • 我明白了......在这种情况下,存储值的类型是intf1 尝试以float 访问它,无论有多少函数调用或有类型转换,所以这种不一致会导致 UB...谢谢你的简明解释。
【解决方案2】:

适合在具有已发布 ABI 的平台上进行低级编程的编译器将提供一种方法,强制以与该 ABI 一致的方式执行函数调用,这反过来又会强制执行跨越要“以环境的文档化方式”处理的函数调用边界。这种支持是标准的作者认为超出其管辖范围的“流行扩展”。设计和配置为适合低级编程的编译器将支持此类结构,而不管标准是否需要它,而那些设计和配置不适合此类目的的编译器不应用于它们。

【讨论】:

    猜你喜欢
    • 2021-12-10
    • 1970-01-01
    • 2016-02-24
    • 2015-10-15
    • 2019-02-20
    • 2020-04-11
    • 2017-02-25
    • 1970-01-01
    相关资源
    最近更新 更多