【问题标题】:A cast that is breaking strict-aliasing rules违反严格混叠规则的演员表
【发布时间】:2011-04-15 09:32:11
【问题描述】:

我有一个采用 unsigned long* 的函数,需要将其传递给采用 unsigned int* 的外部库,并且在此平台上 unsigned int/long 的大小相同。

void UpdateVar(unsigned long* var) {
   // this function will change the value at the address of var
   ExternalLibAtomicUpdateVar((unsigned int*)var); // lib atomically updates variable
}

这会生成一个警告,指出它违反了严格的别名规则。有什么解决办法吗?

谢谢

编辑:我很抱歉不清楚。该代码是一个原子更新,所以绕过库来存储它不是一种选择。我可以下到汇编,但我想在 C++ 中执行此操作。

【问题讨论】:

  • 只适用于单个对象或长/整数数组?
  • 这是对单个 32 位内存的原子存储。

标签: c++ reinterpret-cast strict-aliasing type-punning


【解决方案1】:

C 标准中没有规定intlong 必须具有相同的大小;此外,即使它们确实具有相同的大小,标准中也没有任何规定要求它们具有相同的表示形式(除此之外,它们可能具有不兼容的填充位和陷阱表示组合,因此这两种类型之间的别名无法提供任何有用的目的)。

该标准的作者不想强制实施者针对intlong 之间的别名无法识别此类别名的平台。他们也不想编写适用于某些平台(别名将服务于目的的平台)但不适用于其他平台(不适用的平台)的规则。相反,他们认为编写高质量编译器的人会在有用的情况下尝试识别别名。

能够使用指向一种 32 位类型的指针来读取和写入具有相同表示的另一种 32 位类型的值显然很有用,尤其是当 API 被拆分为它们期望的类型时。如果平台上的某些常见 API 使用 int* 表示 32 位值,而其他 API 使用 long*,则该平台的 quality 通用实现必须允许使用指针访问任一类型的数据其他的。

然而,不幸的是,一些编译器的作者更感兴趣的是快速处理某个程序子集,而不是有效地处理更大的程序子集,如果需要在它们之间交换数据,则不能依赖它来生成有用的代码。除非完全禁用别名分析,否则使用相同数据表示但不同命名类型的 API。当然,如果目标是适合在微控制器上通用使用的 C 语言方言,那么这些问题就无关紧要了。

【讨论】:

    【解决方案2】:
    void UpdateVar(unsigned long* var) {
       unsigned int x = static_cast<unsigned int>(*var);
       ExternalLibUpdateVar(&x);
       *var = static_cast<unsigned long>(x);
    }
    

    【讨论】:

    • 对不起;没有注意到 C++ 标签
    • 在这种情况下static_castreinterpret_cast 之间的真正区别是什么?
    • 现在不同了。想象一下ExternalLibUpdate 将传递的地址存储在某处。它将存储本地x 的地址,而不是var 中的地址。
    • @IceDane 我相信这里 reinterpret_cast 的行为是未定义的——据我所知,唯一可以保证的是,如果你将 reinterpret_cast 转换为更大的类型,然后再返回,你将获得原始值返回
    • 我编辑了我的原始帖子,以反映外部库是一个原子更新,所以我不允许自己绕过它来存储它。
    【解决方案3】:

    这应该可行:

    void UpdateVar(unsigned long* var) {
       // this function will change the value at the address of var
       ExternalLibUpdateVar(reinterpret_cast<unsigned int*>(var));
    }
    

    【讨论】:

    • 如果 sizeof(long) != sizeof(int) 很危险
    • 他在原帖中说,他们保证在他的平台上大小相同。但是,是的,你是对的。
    • +1。在某些条件下,我认为这实际上是合适的。但这确实取决于具体情况,如果不满足条件,我会在程序中使用某种sizeof(int)==sizeof(long) 检查使编译失败——C++0x 的static_cast 有人吗? :-)
    • 我使用这样的宏来执行静态断言:#define static_assert(x) extern char static_assert[(x) ? 1:-1]
    • 我在我的代码中做了一个 static_assert 但我看不出这如何解决别名问题。
    猜你喜欢
    • 2015-10-04
    • 2018-03-20
    • 1970-01-01
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 2017-02-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多