我现在有这个代码:
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];
}