您建议将这个数组转换为整数的这两种方法中的哪一种?

时间:2010-11-06 09:45:50

标签: c++ arrays performance integer

考虑以下要转换为单个无符号整数的字节数组:

unsigned char arr[3] = {0x23, 0x45, 0x67};

每个字节代表整数的等效字节,现在你会特别建议以下一种方法:

unsigned int val1 = arr[2] << 16 | arr[1] << 8 | arr[0];
//or
unsigned int val2=arr[0];
*((char *)&val2+1)=arr[1];
*((char *)&val2+2)=arr[2];

6 个答案:

答案 0 :(得分:6)

我更喜欢第一种方法,因为它是便携式的。第二个问题不是endianness问题。

答案 1 :(得分:4)

第一个更快,在x86 asm中翻译。这取决于你的架构。通常编译器能够非常好地优化第一个表达式,并且它也更加便携

答案 2 :(得分:4)

这取决于您的特定处理器,很多

例如,在PowerPC上,第二种形式 - 通过字符指针编写 - 会遇到一个棘手的实现细节,称为 load-hit-store 。这是当您存储到内存中的某个位置时发生的CPU停顿,然后在存储完成之前再次读取它。在存储完成之前,加载操作无法完成(大多数PPC没有内存存储转发),并且存储可能需要很多周期才能从CPU输出到内存缓存。

由于存储和算术单元在流水线中的排列方式,CPU必须完全冲洗流水线直到存储完成:这可能是一个20个周期或更长时间的停顿,在此期间CPU已经停止运行。一般来说,写入内存然后立即回读它在这个平台上是非常糟糕的。因此在这种情况下,顺序位移将更快,因为它们都发生在寄存器上,并且不会导致流水线停顿。

在Pentium系列上,情况可能完全颠倒,因为芯片组 具有存储转发和快速堆栈架构,以及相对较少的架构寄存器。在Core Duos和i7s上,它可能会再次反转,因为它们的管道非常深。

请记住:并非每个操作码需要一个周期。 CPU并不简单,superscalar pipesdata hazards之类的操作可能会导致指令占用很多周期,或者甚至是每个周期发生的许多指令,具体取决于您如何安排代码。

所有这一切只是为了强调这一点:这种优化非常特定于特定的编译器和芯片组。所以你必须编译,测试和测量。

答案 3 :(得分:2)

性能取决于编译器和机器。例如,在我使用g64 4.4.5在x64上进行的实验中,第二个稍快一些,而其他人报告第一个更快。因此,我建议坚持使用第一个,因为它更干净(没有强制转换)并且更安全(没有字节序问题)。

答案 4 :(得分:1)

我相信bitshift将是最快的解决方案。在我看来,CPU可以只滑动值,但直接转到地址,就像你的第二个例子一样,它将不得不使用许多临时存储。

答案 5 :(得分:1)

我建议使用union解决方案:

union color { 
    // first representation (member of union) 
    struct s_color { 
        unsigned char a, b, g, r;
    } uc_color;

    // second representation (member of union) 
    unsigned int int_color; 
};

int main()
{
  color a;
  a.int_color = 0x23567899;
  a.uc_color.a;
  a.uc_color.b;
  a.uc_color.g;
  a.uc_color.r;
}

注意它依赖于平台(哪个endianess)