应用两个显式类型转换的原因是什么?
if (unlikely(val != (long)(char)val)) {
从lxml的源包中的lxml.etree.c源文件中获取的代码。
答案 0 :(得分:10)
这是一种廉价的方式来检查高位中是否有任何垃圾。上面的8位,24位或56位(取决于sizeof(val))的char铸造印章然后将其提升回来。如果char已签名,它也将签名扩展。
更好的测试可能是:
if (unlikely(val & ~0xff)) {
或
if (unlikely(val & ~0x7f)) {
取决于此测试是否关心第7位。
只是为了笑容和完整,我写了以下测试代码:
void RegularTest(long val)
{
if (val != ((int)(char)val)) {
printf("Regular = not equal.");
}
else {
printf("Regular = equal.");
}
}
void MaskTest(long val)
{
if (val & ~0xff) {
printf("Mask = not equal.");
}
else {
printf("Mask = equal.");
}
}
以下是在Visual Studio 2010中调试中转换的演员代码:
movsx eax, BYTE PTR _val$[ebp]
cmp DWORD PTR _val$[ebp], eax
je SHORT $LN2@RegularTes
这是掩码:
mov eax, DWORD PTR _val$[ebp]
and eax, -256 ; ffffff00H
je SHORT $LN2@MaskTest
在发布中,我得到了演员代码:
movsx ecx, al
cmp eax, ecx
je SHORT $LN2@RegularTes
在发布中,我得到了掩码代码:
test DWORD PTR _val$[ebp], -256 ; ffffff00H
je SHORT $LN2@MaskTest
那是怎么回事?在转换的情况下,它正在使用符号扩展执行一个字节mov(ha!bug - 代码不一样,因为字符被签名)然后比较并且完全偷偷摸摸,编译器/链接器也使这个函数使用寄存器传递为了论证。在发布中的掩码代码中,它将所有内容都折叠成一条测试指令。
哪个更快?打败我 - 坦白说,除非你在非常慢的CPU上运行这种测试或运行数十亿次,否则无关紧要。至少没有。
因此,在这种情况下,答案是编写明确其意图的代码。我希望C / C ++骑师能够查看掩码并理解其意图,但如果你不喜欢它,你应该选择这样的东西:
#define BitsAbove8AreSet(x) ((x) & ~0xff)
#define BitsAbove7AreSet(x) ((x) & ~0x7f)
或:
inline bool BitsAbove8AreSet(long t){return(t& ~0xff)!= 0; } //使它成为一个好的bool inline bool BitsAbove7AreSet(long t){return(t& ~0x7f)!= 0; }
并使用谓词而不是实际代码。
总的来说,我认为“它便宜吗?”除非你在一些非常具体的问题领域工作,否则这个问题并不是一个特别好的问题。例如,我从事图像处理工作,当我从一个图像到另一个图像进行某种操作时,我经常会看到如下代码:
BYTE *srcPixel = PixelOffset(src, x, y, srcrowstride, srcdepth);
int srcAdvance = PixelAdvance(srcrowstride, right, srcdepth);
BYTE *dstPixel = PixelOffset(dst, x, y, dstrowstride, dstdepth);
int dstAdvance = PixelAdvance(dstrowstride, right, dstdepth);
for (y = top; y < bottom; y++) {
for (x=left; x < right; x++) {
ProcessOnePixel(srcPixel, srcdepth, dstPixel, dstdepth);
srcPixel += srcdepth;
dstPixel += dstdepth;
}
srcPixel += srcAdvance;
dstPixel += dstAdvance;
}
在这种情况下,假设ProcessOnePixel()实际上是一块内联代码,将被执行数十亿次数十亿次。在这种情况下,我非常关心不做函数调用,不做冗余工作,不重新检查值,确保计算流程将转化为明智地使用寄存器的东西,等等。但我实际主要关心的是代码可以被下一个可怜的骗子(可能是我)阅读,他必须看看它。
在我们当前的编码世界中,对于几乎每个问题领域来说,花费一点时间预先确保您的代码易于阅读和维护,而不是担心门外的性能。 / p>
答案 1 :(得分:1)
如果val为long,则(char)将除去最后8位以外的所有内容。 (长)将它投回去进行比较。
答案 2 :(得分:1)
思考:
施放到char:掩盖8个低位,
强制转换为:将值恢复为signed(如果char未签名)。