联合是否比现代编译器更有效?

| 考虑简单的代码:
UINT64 result;
UINT32 high, low;
...
result = ((UINT64)high << 32) | (UINT64)low;
现代编译器是将其转换为高电平时的实际偏移,还是将其优化为简单复制到正确的位置? 如果不是这样,那么使用工会似乎比大多数人似乎使用的转变更为有效。但是,让编译器进行优化是理想的解决方案。 我想知道当人们需要额外的性能时我该如何建议他们。     
已邀请:
我编写了以下(希望有效)测试:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

void func(uint64_t x);

int main(int argc, char **argv)
{
#ifdef UNION
  union {
    uint64_t full;
    struct {
      uint32_t low;
      uint32_t high;
    } p;
  } result;
  #define value result.full
#else
  uint64_t result;
  #define value result
#endif
  uint32_t high, low;

  if (argc < 3) return 0;

  high = atoi(argv[1]);
  low = atoi(argv[2]);

#ifdef UNION
  result.p.high = high;
  result.p.low = low;
#else
  result = ((uint64_t) high << 32) | low;
#endif

  // printf(\"%08x%08x\\n\", (uint32_t) (value >> 32), (uint32_t) (value & 0xffffffff));
  func(value);

  return 0;
}
运行未优化输出the2 un的差异:
<   mov -4(%rbp), %eax
<   movq    %rax, %rdx
<   salq    $32, %rdx
<   mov -8(%rbp), %eax
<   orq %rdx, %rax
<   movq    %rax, -16(%rbp)
---
>   movl    -4(%rbp), %eax
>   movl    %eax, -12(%rbp)
>   movl    -8(%rbp), %eax
>   movl    %eax, -16(%rbp)
我不了解汇编程序,因此我很难对其进行分析。但是,似乎在非联盟(顶部)版本上发生了预期的变化。 但是启用优化
-O2
,输出是相同的。因此,生成了相同的代码,并且两种方式都将具有相同的性能。 (Linux / AMD64上的gcc版本4.5.2) 优化的
-O2
代码的部分输出(带有或不带有联合):
    movq    8(%rsi), %rdi
    movl    $10, %edx
    xorl    %esi, %esi
    call    strtol

    movq    16(%rbx), %rdi
    movq    %rax, %rbp
    movl    $10, %edx
    xorl    %esi, %esi
    call    strtol

    movq    %rbp, %rdi
    mov     %eax, %eax
    salq    $32, %rdi
    orq     %rax, %rdi
    call    func
片段由
if
线产生的跳转后立即开始。     
现代编译器比您想像的要聪明;-)(所以,是的,我认为您可以期望任何不错的编译器都会发生重大变化)。 无论如何,我将使用语义更接近您实际尝试执行的选项。     
如果这应该是平台无关的,那么唯一的选择就是在这里使用shift。 使用
union { r64; struct{low;high}}
,您无法确定将映射到哪个低/高场。考虑一下耐力。 现代编译器很好地处理了这种变化。     
编辑:此响应基于没有强制转换的OP的代码的早期版本 此代码
result = (high << 32) | low;
实际上会产生未定义的结果...因为使用
high
,您要将32位值移动32位(值的宽度),结果将是不确定的,并且将取决于编译器和OS平台决定应对这一转变。然后,该不确定的移位的结果将与ѭ11或,由于您将一个未定义的值与定义的值进行比对,因此它也将是不确定的,因此最终结果很可能不是随心所欲的64位值。例如,OSX 10.6上的“ 2”发出的代码如下:
movl    -4(%rbp), %eax      //retrieving the value of \"high\"
movl    $32, %ecx          
shal    %cl, %eax           //performing the 32-bit shift on \"high\"
orl    -8(%rbp), %eax       //OR\'ing the value of \"low\" to the shift op result
因此,您可以看到,移位仅发生在具有32位汇编命令的32位寄存器中的32位值上……结果最终与ѭ14same完全相同,而没有任何移位,因为在这种情况下,
shal $32, %eax
只是返回in16ѭ中的原始值。您没有得到64位结果。 为了避免这种情况,请将
high
转换为
uint64_t
,例如:
result = ((uint64_t)high << 32) | low;
    

要回复问题请先登录注册