在一行中应用两个显式类型转换的原因是什么? [英] What's the reason behind applying two explicit type casts in a row?

查看:85
本文介绍了在一行中应用两个显式类型转换的原因是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用两个显式类型转换的原因是什么?

  if val!=(long)(char)val)){

取自lxml.etree.c源文件从lxml的源包。

解决方案

这是一个便宜的方式来检查是否有高位的任何垃圾。上部8,24或56位(取决于sizeof(val))的字符铸造,然后促进它回来。



更好的测试可能是:

  if(likely(val&〜0xff)){



  if(likely(val&〜0x7f)){

取决于这个测试是否关于位7。



为了咧嘴和完整性,我写了以下测试代码:

  void RegularTest(long val)
{
if(val!= (char)val)){
printf(Regular = not equal。);
}
else {
printf(Regular = equal。);
}
}

void MaskTest(long val)
{
if(val&〜0xff){
printf =不等于);
}
else {
printf(Mask = equal。);
}
}

这里是转换代码在debug 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短裤$ LN2 @ MaskTest

那么发生了什么事?在cast的情况下,它做一个带符号扩展的字节mov(ha!bug - 代码不一样,因为chars被签名),然后一个比较和完全鬼祟,编译器/链接器也使这个函数使用寄存器传递为参数。在发布的掩码中,它已将所有内容折叠成单个测试指令。



哪个更快?打我,坦率地说,除非你在一个非常慢的CPU上运行这种测试或运行它几十亿次,这没关系。



因此,这种情况下的答案是编写清楚其意图的代码。我希望一个C / C ++骑师看看面具代码,并了解其意图,但如果你不喜欢,你应该选择类似这样的东西:

  #define BitsAbove8AreSet(x)(x)&〜0xff)
#define BitsAbove7AreSet(x)((x)&〜0x7f)
/ code>



或:



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 for(x = left; x< right; x ++){
ProcessOnePixel(srcPixel,srcdepth,dstPixel,dstdepth) ;
srcPixel + = srcdepth;
dstPixel + = dstdepth;
}
srcPixel + = srcAdvance;
dstPixel + = dstAdvance;
}

在这种情况下,假设ProcessOnePixel()实际上是一个内联块代码将执行数十亿和数十亿次。在这种情况下,我关心一大堆不做功能调用,不做冗余工作,不重新检查值,确保计算流将转换为将明智地使用寄存器等等,但我的实际主要关注的是代码



在我们当前的编码世界中,几乎每一个问题都是FAR FAR CHEAPER领域花费一点时间,确保您的代码易于阅读和维护,而不是担心性能出门。


What's the reason behind applying two explicit type casts as below?

if (unlikely(val != (long)(char)val)) {

Code taken from lxml.etree.c source file from lxml's source package.

解决方案

That's a cheap way to check to see if there's any junk in the high bits. The char cast chops of the upper 8, 24 or 56 bits (depending on sizeof(val)) and then promotes it back. If char is signed, it will sign extend as well.

A better test might be:

if (unlikely(val & ~0xff)) {

or

if (unlikely(val & ~0x7f)) {

depending on whether this test cares about bit 7.

Just for grins and completeness, I wrote the following test code:

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

And here's what the cast code turns into in debug in visual studio 2010:

movsx   eax, BYTE PTR _val$[ebp]
cmp DWORD PTR _val$[ebp], eax
je  SHORT $LN2@RegularTes

this is the mask code:

mov eax, DWORD PTR _val$[ebp]
and eax, -256               ; ffffff00H
je  SHORT $LN2@MaskTest

In release, I get this for the cast code:

movsx   ecx, al
cmp eax, ecx
je  SHORT $LN2@RegularTes

In release, I get this for the mask code:

test    DWORD PTR _val$[ebp], -256      ; ffffff00H
je  SHORT $LN2@MaskTest

So what's going on? In the cast case it's doing a byte mov with sign extension (ha! bug - the code is not the same because chars are signed) and then a compare and to be totally sneaky, the compiler/linker has also made this function use register passing for the argument. In the mask code in release, it has folded everything up into a single test instruction.

Which is faster? Beats me - and frankly unless you're running this kind of test on a VERY slow CPU or are running it several billion times, it won't matter. Not in the least.

So the answer in this case, is to write code that is clear about its intent. I would expect a C/C++ jockey to look at the mask code and understand its intent, but if you don't like that, you should opt for something like this instead:

#define BitsAbove8AreSet(x) ((x) & ~0xff)
#define BitsAbove7AreSet(x) ((x) & ~0x7f)

or:

inline bool BitsAbove8AreSet(long t) { return (t & ~0xff) != 0; } // make it a bool to be nice inline bool BitsAbove7AreSet(long t) { return (t & ~0x7f) != 0; }

And use the predicates instead of the actual code.

In general, I think "is it cheap?" is not a particularly good question to ask about this unless you're working in some very specific problem domains. For example, I work in image processing and when I have some kind of operation going from one image to another, I often have code that looks like this:

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

And in this case, assume that ProcessOnePixel() is actually a chunk of inline code that will be executed billions and billions of times. In this case, I care a whole lot about not doing function calls, not doing redundant work, not rechecking values, ensuring that the computational flow will translate into something that will use registers wisely, etc. But my actual primary concern is that the code can be read by the next poor schmuck (probably me) who has to look at it.

And in our current coding world, it is FAR FAR CHEAPER for nearly every problem domain to spend a little time up front ensuring that your code is easy to read and maintain than it is to worry about performance out of the gate.

这篇关于在一行中应用两个显式类型转换的原因是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆