繁体   English   中英

使用指针遍历结构

[英]Iterate through a struct with a pointer

我目前有这个代码:

struct LAYOUT {
            WORD a [8] = {::Rook, ::Knight, ::Bishop, ::Queen, ::King, ::Bishop, ::Knight, ::Rook};
            WORD b [8] = {::Pawn};
            WORD empty [32] = {::None};
            WORD c [8] = {::Pawn+0x6};
            WORD d [8] = {::Rook+0x6, ::Knight+0x6, ::Bishop+0x6, ::Queen+0x6, ::King+0x6, ::Bishop+0x6, ::Knight+0x6, ::Rook+0x6};
        }chessLayout;
LAYOUT* chessboard = &chessLayout;

::Rook等全局enum字段表示一个单词,例如: 0x2656

我这里的目标是枚举这个结构中的所有元素,所以我写了这段代码:

for(int i = 0; sizeof(LAYOUT) / 2;i++){
     printf("%x", *(reinterpret_cast<WORD*>(chessboard+i)));
}

然而,这将返回第一个值,但随后返回不相关的垃圾值,而不是结构中的元素。

有任何想法吗?

提前致谢

在声明中

LAYOUT* chessboard = &chessLayout;

/* ... */

for(int i = 0; sizeof(LAYOUT) / 2;i++){
     printf("%x", *(reinterpret_cast<WORD*>(chessboard+i)));
}

指针chessboard递增,其类型为LAYOUT* 这将使指针沿“i * sizeof(LAYOUT)”字节移动,而您想要的是移动到下一个 WORD。

因此,表达式应该看起来像这样(我在演员表之外):

for(int i = 0; i < sizeof(LAYOUT) / 2; ++i){
     printf("%x", *(reinterpret_cast<WORD*>(chessboard)+i));
}

编辑:正如@Jarod42 指出的那样,您可能会很快遇到 UB,因为我们正在迭代数组 a 的“结束迭代器”。

确切的解释有时不清楚,并在 SO 和其他地方引起了许多讨论。

这是一个关于此的线程并使用 C++17 offsetof功能在这种情况下应该有所帮助: 在标准布局 object(例如,使用 offsetof)中进行指针运算时,我们是否需要使用 std::launder?

我相信对此的详细讨论很重要,但有足够的活跃线程,因此在此不再赘述。

为了避免使用 UB 刺激探戈,我会以相反的方式执行此操作,让布局包含整个数据的数组,而a,b,c,d将是吸气剂。 即使像下面的代码中那样强制转换指针也会是边缘行走,但是我们可以遍历数据,而不用担心它可能会被填充词打断。

using WORD = unsigned short;

namespace LayoutNS { 
      
struct Layout {
    WORD data[64];
    
    template <size_t N>
    using line = WORD [N];
    
    template <size_t N>
    line<N>* operator[] ( line<N>* (*f)(Layout&)  )
    {
        return (*f)(*this);
    }   
};

}

using LAYOUT = LayoutNS::Layout;

// better to avoid such cast either, can we go just with a pointer? Or return a copy?
LAYOUT::line<8>* line_a (LAYOUT& l) { return (LAYOUT::line<8>*)(l.data); }
LAYOUT::line<8>* line_b (LAYOUT& l) { return (LAYOUT::line<8>*)(l.data+8); }
LAYOUT::line<32>* empty (LAYOUT& l) { return (LAYOUT::line<32>*)(l.data+16); }
LAYOUT::line<8>* line_c (LAYOUT& l) { return (LAYOUT::line<8>*)(l.data+48); }
LAYOUT::line<8>* line_d (LAYOUT& l) { return (LAYOUT::line<8>*)(l.data+56); }

int main()
{
    LAYOUT test = {};
    auto test_a = test[line_a];

    std::cout << (*test_a)[1];
}

避免间接级别和 C++11 功能的简化版本:

struct LAYOUT {
    WORD data[64];
       
    WORD* operator[] ( WORD* (*f)(LAYOUT&)  )
    {
        return (*f)(*this);
    }   
};

WORD* line_a (LAYOUT& l) { return (l.data); }
WORD* line_b (LAYOUT& l) { return (l.data+8); }
WORD* empty (LAYOUT& l) { return (l.data+16); }
WORD* line_c (LAYOUT& l) { return (l.data+48); }
WORD* line_d (LAYOUT& l) { return(l.data+56); }

int main()
{
    LAYOUT test = {{1,3,4,5}};
    auto test_a = test[line_a];

    std::cout << test_a[1];
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM