零初始化器比memset更快吗?

时间:2016-11-24 12:24:30

标签: c performance memset

我维护旧版C代码,在许多地方,它们都有像int a[32];这样的小数组,后跟memset(a, 0, sizeof a);来初始化它。

我正在考虑将其重构为int a[32] = {0};并删除memset。

问题是:使用零初始值设定项通常会产生比调用memset更快的代码吗?

1 个答案:

答案 0 :(得分:3)

TL; DR:使用初始化程序 - 它永远不会比memset()更糟。

这取决于你的编译器。 它不应该比调用memset()更慢(因为调用memset()是编译器可用的一个选项)。

初始化程序比强制覆盖数组更容易阅读;如果将元素类型更改为all-bit-zero不是您想要的内容,它也会很好地适应。

作为一项实验,让我们看看GCC对此做了什么:

#include <string.h>

int f1()
{
    int a[32] = {0};
    return a[31];
}

int f2()
{
    int a[32];
    memset(a, 0, sizeof a);
    return a[31];
}

使用gcc -S -std=c11进行编译得出:

f1:
.LFB0:
    .file 1 "40786375.c"
    .loc 1 4 0
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $8, %rsp
    .loc 1 5 0
    leaq    -128(%rbp), %rdx
    movl    $0, %eax
    movl    $16, %ecx
    movq    %rdx, %rdi
    rep stosq
    .loc 1 6 0
    movl    -4(%rbp), %eax
    .loc 1 7 0
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
f2:
.LFB1:
    .loc 1 10 0
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    addq    $-128, %rsp
    .loc 1 12 0
    leaq    -128(%rbp), %rax
    movl    $128, %edx
    movl    $0, %esi
    movq    %rax, %rdi
    call    memset@PLT
    .loc 1 13 0
    movl    -4(%rbp), %eax
    .loc 1 14 0
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

显示f1()使用rep stosq作为初始化程序,而f2()具有函数调用,与C代码完全相同。 memset()很可能对大型数组有更高效的矢量化实现,但对于像这样的小型数组,函数调用开销可能会超过任何好处。

如果我们将a声明为volatile,我们会看到启用优化后会发生什么(gcc -S -std=c11 -O3):

f1:
.LFB4:
    .cfi_startproc
    subq    $16, %rsp
    .cfi_def_cfa_offset 24
    xorl    %eax, %eax
    movl    $16, %ecx
    leaq    -120(%rsp), %rdi
    rep stosq
    movl    4(%rsp), %eax
    addq    $16, %rsp
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc
f2:
.LFB5:
    .cfi_startproc
    subq    $16, %rsp
    .cfi_def_cfa_offset 24
    xorl    %eax, %eax
    movl    $16, %ecx
    leaq    -120(%rsp), %rdx
    movq    %rdx, %rdi
    rep stosq
    movl    4(%rsp), %eax
    addq    $16, %rsp
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc

您可以看到这两个函数现在编译为相同的代码。