好吧,所以Stockfish项目有这么多代码,允许存储两个整数(预计在〜[-16000,16000]之间
编辑:我忘了提到,这个的全部目的是我们可以一次加两个整数。 IEa1+a2,b1+b2 = Decode(Encode(a1,b1) + Encode(a2,b2))
constexpr int make_score(int mg, int eg) {
return (int)((unsigned int)eg << 16) + mg;
}
inline int eg_value(int s) {
union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s + 0x8000) >> 16) };
return (int)eg.s;
}
inline int mg_value(int s) {
union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s)) };
return (int)mg.s;
}
我想将其转换为C.显然我可以跳过内联和constexpr限定符。但是,不允许内联联合定义。另外,我宁愿不使用联盟,因为它似乎不合适IMO。
这是我在C中所拥有的。
#define MakeScore(mg, eg) ((int)((unsigned int)(eg) << 16) + (mg))
#define ScoreMG(s) ((int16_t)((uint16_t)((unsigned)((s)))))
#define ScoreEG(s) ((int16_t)((uint16_t)((unsigned)((s) + 0x8000) >> 16)))
从我的测试中我可以看出,当比较c ++和c程序时,这两个版本的行为相同。主要区别在于我已经替换了mg.s或者eg.s的最后一步(获得了union的签名部分),并使用了一个简单的转换为int16_t。
对任何C标准的任何想法或指示(使用C98,但任何版本在这里可能都相同)将不胜感激。
答案 0 :(得分:2)
代码可以在C ++中简化,然后是有效的C:
int eg_value2(int s) {
return ((unsigned)s + 0x8000u) >> 16;
}
它生成与原始组件相同的组件:
lea eax,[rdi+0x8000]
shr eax,0x10
ret
顺便说一下,原始代码写入了union的一个成员,然后从另一个成员读取,这是C ++中未定义的行为。见Accessing inactive union member and undefined behavior?