我有一个使用#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并将常量添加到符号表中,而不是为其占用存储空间。
答案 0 :(得分:14)
这是C和C ++之间的区别很重要的另一种情况。
在C中,const int FOO
具有外部链接,因此必须包含在二进制文件中。
使用g ++或clang ++进行编译可以为您提供所需的优化,因为FOO
在C ++中具有内部链接。
您可以通过以下方式明确请求FOO
的内部链接,从而在C模式下实现优化:
static const int FOO = 1;
启用了链接时间优化(-flto
)的clang和gcc甚至都可以删除未使用的符号,即使在外部链接时也是如此。 (实时with和without LTO。)
答案 1 :(得分:3)
在第二个程序中使用变量FOO
的事实意味着它必须存在于某个地方,因此编译器需要将其分配到某个地方。
在#define
情况下,没有变量-预处理器将文本“ FOO”替换为文本“ 1” a,因此对printf()
的调用传递了一个常量值,而不是变量。