为什么clang不像#define那样优化全局const?

时间:2019-01-18 14:06:51

标签: c++ c optimization clang constants

我有一个使用#define常量的测试程序:

#include <stdio.h>

#define FOO 1

int main()
{
    printf("%d\n", FOO);

    return 0;
}

当使用“ Apple LLVM版本10.0.0(clang-1000.11.45.5)”进行编译时,我得到了8432字节的可执行文件。这是程序集清单:

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 14
    .globl  _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    leaq    L_.str(%rip), %rdi
    movl    $1, %esi
    movl    $0, -4(%rbp)
    movb    $0, %al
    callq   _printf
    xorl    %esi, %esi
    movl    %eax, -8(%rbp)          ## 4-byte Spill
    movl    %esi, %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "%d\n"


.subsections_via_symbols

现在,我将#define FOO 1替换为const int FOO = 1;。可执行文件现在为8464字节,程序集列表如下所示:

.section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 14
    .globl  _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    leaq    L_.str(%rip), %rdi
    movl    $1, %esi
    movl    $0, -4(%rbp)
    movb    $0, %al
    callq   _printf
    xorl    %esi, %esi
    movl    %eax, -8(%rbp)          ## 4-byte Spill
    movl    %esi, %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .section    __TEXT,__const
    .globl  _FOO                    ## @FOO
    .p2align    2
_FOO:
    .long   1                       ## 0x1

    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "%d\n"


.subsections_via_symbols

因此它实际上声明了一个FOO变量,使可执行文件增大了32个字节。 我在-O3优化级别上获得了相同的结果。

那是为什么?通常,the compiler should be intelligent enough to optimize并将常量添加到符号表中,而不是为其占用存储空间。

2 个答案:

答案 0 :(得分:14)

这是C和C ++之间的区别很重要的另一种情况。

在C中,const int FOO具有外部链接,因此必须包含在二进制文件中。

使用g ++或clang ++进行编译可以为您提供所需的优化,因为FOO在C ++中具有内部链接。

您可以通过以下方式明确请求FOO的内部链接,从而在C模式下实现优化:

static const int FOO = 1;

启用了链接时间优化(-flto)的clang和gcc甚至都可以删除未使用的符号,即使在外部链接时也是如此。 (实时withwithout LTO。)

答案 1 :(得分:3)

在第二个程序中使用变量FOO的事实意味着它必须存在于某个地方,因此编译器需要将其分配到某个地方。

#define情况下,没有变量-预处理器将文本“ FOO”替换为文本“ 1” a,因此对printf()的调用传递了一个常量值,而不是变量。