有和没有'静态'的速度

时间:2014-12-12 15:30:21

标签: c

我知道'静电'是关于范围的,但我有一个问题:访问哪个功能/变量会更快:一个静态的'一个与否? 哪个代码会更快:

#include <stdio.h>

int main(){
   int count;
   for (count=0;count<1000;++count)
      printf("%d\n",count);
   return 0;
}

#include <stdio.h>

int main(){
   static int count;
   for (count=0;count<1000;++count)
      printf("%d\n",count);
   return 0;
}

在我的代码中,我处理的是非常大的数字(使用无符号长整数),并且我每秒访问和增加它们大约4.000.000次。 此代码不是我正在处理的代码,它只是一个示例

1 个答案:

答案 0 :(得分:1)

作为善意的表示,我已经编制了一个我们可以实际推理的程序。

#include <stdint.h>
#include <stdio.h>

int
main()
{
  static const uint64_t a = 1664525UL;
  static const uint64_t c = 1013904223UL;
  static const uint64_t m = (1UL << 31);
  static uint32_t x = 1;
  register unsigned i;
  for (i = 0; i < 1000000000U; ++i)
    x = (a * x + c) % m;
  printf("%d\n", x);
  return 0;
}

它将简单地计算由简单线性同余生成器返回的伪随机序列的十亿分之一元素。我们必须做一些比简单地递增计数器更难的事情,否则编译器将优化整个循环。

以下是我编译的方法(x86_64 GNU / Linux上的GCC 4.9.1):

$ gcc -o non-static -Dstatic= -Wall -O3 main.c
$ gcc -o static               -Wall -O3 main.c

要获取不带static的版本,我们只需在编译器命令行上#define

运行这两个程序需要2.36秒,这意味着没有可衡量的性能差异。

为了找出原因,我想查看汇编代码。

$ gcc -S -o non-static.s -Dstatic= -Wall -O3 main.c
$ gcc -S -o static.s               -Wall -O3 main.c

我们发现GCC为内循环生成了相同的机器代码,并将static变量的特殊处理移出循环,这是我们应该从一个好的编译器中得到的。

static的相关代码:

main:
.LFB11:
    .cfi_startproc
    movl    x.2266(%rip), %esi
    movl    $1000000000, %eax
    .p2align 4,,10
    .p2align 3
.L2:                                 # BEGIN LOOP
    imull   $1664525, %esi, %esi
    addl    $1013904223, %esi
    andl    $2147483647, %esi
    subl    $1, %eax
    jne .L2                          # END LOOP
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    movl    $.LC0, %edi
    xorl    %eax, %eax
    movl    %esi, x.2266(%rip)
    call    printf
    xorl    %eax, %eax
    addq    $8, %rsp
    .cfi_def_cfa_offset 8
    ret

且没有:

main:
.LFB11:
    .cfi_startproc
    movl    $1000000000, %eax
    movl    $1, %esi
    .p2align 4,,10
    .p2align 3
.L2:                                 # BEGIN LOOP
    imull   $1664525, %esi, %esi
    addl    $1013904223, %esi
    andl    $2147483647, %esi
    subl    $1, %eax
    jne .L2                          # END LOOP
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    movl    $.LC0, %edi
    xorl    %eax, %eax
    call    printf
    xorl    %eax, %eax
    addq    $8, %rsp
    .cfi_def_cfa_offset 8
    ret

这再次强调了许多人在评论中试图表达的内容:我们需要实际的代码来推理性能,我们应该在这样做的同时对其进行基准测试。

此外,您不必过多担心此类事情并且大多数时候都信任您的编译器。专注于编写可读和可维护的代码,如果您有证据证明有必要达到所需的性能,则只会弄乱脏的细节。在您的特定示例中,我看不到声明局部变量static的任何有效理由。这让读者感到不安,不应该这样做。