一些转换为C的C ++仍遵循标准?

时间:2018-04-01 06:19:08

标签: c encoding casting bit-manipulation

好吧,所以Stockfish项目有这么多代码,允许存储两个整数(预计在〜[-16000,16000]之间

编辑:我忘了提到,这个的全部目的是我们可以一次加两个整数。 IE

a1+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,但任何版本在这里可能都相同)将不胜感激。

1 个答案:

答案 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?