代码之家  ›  专栏  ›  技术社区  ›  jonspaceharper

如何从指针类型和指针类型中删除未对齐的说明符

  •  0
  • jonspaceharper  · 技术社区  · 6 年前

    在以x86-64为目标的Windows上,我们有 __unaligned 说明符。 真讨厌。我想:(1)对它进行编译时测试;2)在编译时从说明符中删除说明符;3)当从函数调用中找到它时,将它丢弃。扔掉它碰巧需要 const_cast ,幸运的是,任何解决方案都不容易保存 const -尼斯。

    另外,考虑到 ITEMIDLIST 类型(p[c][u]idlist_absolute,p[c][u]idlist_relative…)在windows shell api中,使用指向指针的指针执行上述操作会很好。

    一个人如何做到这一点?


    这里有一个方便的代码示例:

    int main(int, char**)
    {
        //test that aligned_cast works for non-const pointers
        using AType = int __unaligned *;
        int a_data = 1;
        AType a = &a_data;
        auto aa = aligned_cast<int *>(a);
    
        //check that it works for const pointers
        using BType = const int __unaligned *;
        const int b_data = 2;
        BType b = &b_data;
        auto *bb = aligned_cast<const int *>(b);
    
        //int *bbb = aligned_cast<int *>(b); <--won't compile, good
    
        //check that remove_aligned really is doing its job
        using CType = remove_aligned<AType>::type;
        static_assert (is_aligned<CType>::value, "");
    
        //auto aaa = aligned_cast<int **>(&a); <-- &a cannot be passed as a reference
    
        return 0;
    }
    

    1) 未对齐的 是个奇怪的怪癖 那是在安腾时代之前留下的。它潜入了windows api,所以我们(在windows上)一直在使用它。我们基本上不用 ITEMIDLIST 当我们这样做的时候,我们一般 #define STRICT_TYPE_ITEMIDS 小心踩。问题是 reinterpret_cast -这些类型是 难以置信地 烦人的(然后 康斯特卡斯特 我想摆脱 未对齐的 如果需要,指定符)。

    2)编辑:如果你不相信 未对齐的 不再适用 以x86-64为目标时 ,在godbolt上玩我的答案,看看它是否编译而不使用casting。具体来说,从测试线束更改以下行导致编译失败:

    59   //auto aa = aligned_cast<int *>(a);
    60    int *aa = a; //nope, a is int __unaligned *
    
    1 回复  |  直到 6 年前
        1
  •  0
  •   jonspaceharper    6 年前

    这里有一个可能的内联解释的解决方案。有 三个注意事项:

    1. 这不是一个内置的操作员,所以 int **foo = aligned_cast<int **>(&bar) 出局(结果是 &bar 是一个右值)。
    2. 如果指针本身被标记为不对齐,这将不起作用(我甚至不确定这是不是一件事)。
    3. 它可能会删除指针本身的cv限定( int __unaligned * const 变成 int * )我没有做这个测试,因为我已经做了九个多小时了,而且很累。

    不管怎样,

    #include <utility>
    
    //remove_all_pointers simply wipes out any pointers so we can get to the raw type (plus its cv-qualifiers)
    template <class T>
    struct remove_all_pointers { using type = T; };
    
    template <class T>
    struct remove_all_pointers<T *> { using type = remove_all_pointers<T>; };
    
    template <class T>
    using remove_all_pointers_t = typename remove_all_pointers<T>::type;
    
    //this selector works like is_const, only it catches __unaligned instead
    template<class T>
    struct is_aligned_helper : std::true_type {};
    
    template<class T>
    struct is_aligned_helper<__unaligned T> : std::false_type {};
    
    //wipe all pointers before we check for __unaligned
    template<class T , class = std::enable_if<std::is_pointer_v<T>>>
    struct is_aligned : is_aligned_helper<remove_all_pointers_t<T>> {};
    
    template<class T>
    using is_aligned_v = typename is_aligned<T>::value;
    
    template <class T>
    struct remove_aligned_helper { using type = T; };
    
    template <class T>
    struct remove_aligned_helper<__unaligned T> { using type = T; };
    
    template <class T>
    struct remove_aligned
    {
        //remove the pointer, remove the __unaligned specifier, then put the pointer back
        using type = std::add_pointer_t<
            typename remove_aligned_helper<
                std::remove_pointer_t<T>>::type>;
    };
    
    //we can specialize for pointers to pointers, too
    template <class T>
    struct remove_aligned<T **> {
        using type = std::add_pointer_t<typename remove_aligned<T *>::type>;
    };
    
    template <class T>
    using remove_aligned_t = typename remove_aligned<T>::type;
    
    template <class To, class From, class = std::enable_if<std::is_pointer<From>() && !is_aligned<From>()>>
    constexpr To aligned_cast(From &value) noexcept
    {
        return reinterpret_cast<To>(const_cast<remove_aligned_t<From>>(value));
    }
    
    int main(int, char**)
    {
        //check that it works at all
        using AType = int __unaligned *;
        int a_data = 1;
        AType a = &a_data;
        int * aa = aligned_cast<int *>(a);
        (void)aa;
        //check that it works for const pointers
        using BType = const int __unaligned *;
        const int b_data = 2;
        BType b = &b_data;
        const int *bb = aligned_cast<const int *>(b);
        (void)bb;
        //int *bbb = aligned_cast<int *>(b); //<--won't compile, good
    
        //check that remove_aligned really is doing its job
        using CType = remove_aligned<AType>::type;
        static_assert (is_aligned<CType>::value, "");
    
        //check that T** works
        AType *d = &a;
        int ** aaa = aligned_cast<int **>(d); //<-- &a cannot be passed as a reference
        (void)aaa;
    }
    

    这里是 the code 论上帝。