【问题标题】:Using pointer conversions to store/cast values: Am I breaking the strict aliasing rule?使用指针转换来存储/转换值:我是否违反了严格的别名规则?
【发布时间】:2015-03-25 10:28:15
【问题描述】:

问题与this post有关。

部分权威用户表示,以下代码破坏strict aliasing rules

#include <boost/static_assert.hpp>

template <typename T>
struct MyType {

    private:
    T data;

    public:
    template <typename U>
    operator U () {
        BOOST_STATIC_ASSERT_MSG(sizeof(U) == sizeof(T),"Trying to convert to data type of different size");
        return *((U*) &data);
    }

    template <typename U>
    NeonVectorType<T>& operator =(const U& in) {
        BOOST_STATIC_ASSERT_MSG(sizeof(U) == sizeof(T),"Trying to copy from data type of different size");
        data = *((T*) &in);
        return *this;
    }
}

但是,我从不使用指向 write 数据的指针,也从不共享指向它的指针,因此我无法看到变量中包含的值如何在编译器没有意识到这一点的情况下发生变化正在发生。我的印象是,也许我违反了一些规则,但不是严格的别名规则……

注意:我不知道这有多重要,但我的编译器 (gcc 4.9) 不会发出警告。

【问题讨论】:

  • 我怀疑您将严格的别名规则与指针别名混淆了,指针别名是别名的另一种形式。

标签: c++ pointers c++98 strict-aliasing


【解决方案1】:

*((U*) &amp;data) 将违反严格别名,如果这是 reinterpret_cast 并且类型 U 不允许别名类型 T。允许的类型出现在this list

规则引用both reading and writing

Here 是一篇很好的文章,它解释了规则背后的一些基本原理。

如主严格别名线程中所述,您可以使用memcpy 作为解决方法,例如:

U u;
memcpy( &u, &data, sizeof u );
return u;

在另一个函数中

memcpy( &data, &in, sizeof data );

请注意,类类型的原始字节副本受到一些限制(我认为类必须是 POD,并且您最好确保它们具有相同的布局)。

【讨论】:

  • 如果类型不兼容(U不能给T取别名),为什么编译器不触发警告?编译器是否难以检索此信息?
  • 这种违规检测不是很好。正如我链接的页面中所讨论的,别名传递可能会在代码可识别后很长时间发生
【解决方案2】:

但是,我从不使用指针来写入数据[...]

标准中的语言比这更通用; [basic.life]/7 有:

[...] 一个指针 指向原始对象、引用原始对象的引用或原始对象的名称 对象 [...]

operator= 中,您使用T 类型的左值写入data,而在operator U 中,您使用U 类型的指针来读取它;其中UT 是不相关的,不是字符类型,这是UB。

只需使用memcpy。它保证有效,而且效率很高(试试)!

【讨论】:

  • 确实,memcpy 被优化掉了,生成完全相同的汇编代码!
猜你喜欢
  • 2016-10-09
  • 2021-08-19
  • 2020-04-11
  • 2020-02-08
  • 2018-09-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多