使用指针遍历结构



我现在有这个代码:

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)));
}

则类型为LAYOUT*的指针chessboard被递增。这将使指针沿着";i*sizeof(LAYOUT(";字节,而您想要的是移动到下一个WORD。

因此,表达式应该是这样的(i在cast之外(:

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

EDIT:正如@Jarod42所指出的,当我们迭代通过";结束迭代器";阵列的a.

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

这里有一个关于这一点的线程,并使用C++17offsetof功能,这在上下文中应该有所帮助:当在标准布局对象中进行指针运算时,我们需要使用std::flush吗(例如,使用offsetof(?

我认为对此的详细讨论很重要,但有足够的活动线程,不必在这里重复。

为了避免UB令人兴奋的探戈,我会用相反的方式来做,让布局包含一个完整数据的数组,而a,b,c,d将是getter。即使像下面代码中那样投射指针也是边缘行走,但这样我们就可以迭代数据,而不必担心它可能会被填充字打断。

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];
}

最新更新